【问题标题】:SQLite "LIKE" operator is very slow compared to the "=" operator与“=”运算符相比,SQLite“LIKE”运算符非常慢
【发布时间】:2019-12-19 11:42:09
【问题描述】:

当我在 SQLite 中使用 LIKE 运算符时,与我使用 = 时相比,它非常慢。 使用 = 运算符大约需要 14 毫秒,但是当我使用 LIKE 时,大约需要 440 毫秒。我正在使用DB Browser for SQLite 对此进行测试。这是运行速度很快的查询:

SELECT re.ENTRY_ID, 
       GROUP_CONCAT(re.READING_ELEMENT, '§') AS read_element,
       GROUP_CONCAT(re.FURIGANA_BOTTOM, '§') AS furigana_bottom,
       GROUP_CONCAT(re.FURIGANA_TOP, '§') AS furigana_top,
       GROUP_CONCAT(re.NO_KANJI, '§') AS no_kanji,
       GROUP_CONCAT(re.READING_COMMONNESS, '§') AS read_commonness, 
       GROUP_CONCAT(re.READING_RELATION, '§') AS read_rel,
       GROUP_CONCAT(se.SENSE_ID, '§') AS sense_id, 
       GROUP_CONCAT(se.GLOSS, '§') AS gloss, 
       GROUP_CONCAT(se.POS, '§') AS pos, 
       GROUP_CONCAT(se.FIELD, '§') AS field,
       GROUP_CONCAT(se.DIALECT, '§') AS dialect, 
       GROUP_CONCAT(se.INFORMATION, '§') AS info 
FROM Jmdict_Reading_Element AS re LEFT JOIN 
     Jmdict_Sense_Element AS
     se ON re.ENTRY_ID = se.ENTRY_ID
WHERE re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Reading_Element WHERE READING_ELEMENT = 'example') OR 
      re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Sense_Element WHERE GLOSS = 'example')
 GROUP BY re.ENTRY_ID

当我改变时会变慢

WHERE re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Reading_Element WHERE READING_ELEMENT = 'example') OR 
re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Sense_Element WHERE GLOSS = 'example')

WHERE re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Reading_Element WHERE READING_ELEMENT LIKE 'example') OR 
re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Sense_Element WHERE GLOSS LIKE 'example')

我需要这样做才能使用通配符,例如

WHERE re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Reading_Element WHERE READING_ELEMENT LIKE 'example%') OR 
re.ENTRY_ID IN (SELECT ENTRY_ID FROM Jmdict_Sense_Element WHERE GLOSS LIKE 'example%')

这是数据库本身的链接: https://www.mediafire.com/file/hyuymc84022gzq7/dictionary.db/file

谢谢

【问题讨论】:

    标签: sql performance sqlite database-performance sqlperformance


    【解决方案1】:

    尝试在您正在使用的列上放置全文索引。

    Full Text Indexing

    创建目录

    USE {yourDB}  
    GO  
    CREATE FULLTEXT CATALOG {catalogName}
    WITH ACCENT_SENSITIVITY = OFF
    

    创建索引

    USE {yourDB}  
    GO  
    CREATE FULLTEXT INDEX ON {someTable} ({col1}, {col2})
    ON catalogName
    

    注意 这更方便,但请查看您的排序规则是否不区分大小写,例如'a' = 'A'。通常,排序规则将具有 ci_utf8 例如(ci = 不区分大小写)。我这样做是为了用户和程序员的方便。

    【讨论】:

      【解决方案2】:

      FTS?

      在 Win 10 上使用 DB Browser for sqlite。

      • “快速”查询在 84 毫秒内返回 25 行
      • “慢”查询(使用LIKE "example%")在 1025 毫秒内返回 33 行

      像这样创建 fts4 表:

      create virtual table jre_fts using FTS4(entry_id,reading_element);
      insert into jre_fts select entry_id, reading_element from Jmdict_Reading_Element;
      create virtual table jse_fts using FTS4(entry_id,gloss);
      insert into jse_fts select entry_id, gloss from Jmdict_Sense_Element;
      

      耗时 7390 毫秒,数据库从 70,296KB 增长到 110,708KB。

      像这样修改 WHERE:

       WHERE re.ENTRY_ID IN (SELECT ENTRY_ID FROM jre_fts WHERE READING_ELEMENT MATCH '^example') OR 
      re.ENTRY_ID IN (SELECT ENTRY_ID FROM jse_fts WHERE GLOSS MATCH '^example')
      

      查询在 60 毫秒内返回 33 行。

      我无法测试或分析 FTS 将如何在 reading_element 列上工作,但也许该方法显示出前景。

      【讨论】:

        【解决方案3】:

        我想知道使用HAVING 是否会加快您的查询速度:

        SELECT re.ENTRY_ID, 
               GROUP_CONCAT(re.READING_ELEMENT, '§') AS read_element,
               GROUP_CONCAT(re.FURIGANA_BOTTOM, '§') AS furigana_bottom,
               GROUP_CONCAT(re.FURIGANA_TOP, '§') AS furigana_top,
               GROUP_CONCAT(re.NO_KANJI, '§') AS no_kanji,
               GROUP_CONCAT(re.READING_COMMONNESS, '§') AS read_commonness, 
               GROUP_CONCAT(re.READING_RELATION, '§') AS read_rel,
               GROUP_CONCAT(se.SENSE_ID, '§') AS sense_id, 
               GROUP_CONCAT(se.GLOSS, '§') AS gloss, 
               GROUP_CONCAT(se.POS, '§') AS pos, 
               GROUP_CONCAT(se.FIELD, '§') AS field,
               GROUP_CONCAT(se.DIALECT, '§') AS dialect, 
               GROUP_CONCAT(se.INFORMATION, '§') AS info 
        FROM Jmdict_Reading_Element re LEFT JOIN 
             Jmdict_Sense_Element se
             ON re.ENTRY_ID = se.ENTRY_ID
        GROUP BY re.ENTRY_ID
        HAVING SUM(CASE WHEN re.READING_ELEMENT = 'example' THEN 1 ELSE 0 END) > 0 OR
               SUM(CASE WHEN se.GLOSS = 'example' THEN 1 ELSE 0 END) > 0);
        

        【讨论】:

        • 这并没有加快速度:(
        • @AdenDiamond 。 . .当然不是。我需要删除WHERE 子句。试试这个版本。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-24
        • 2018-12-13
        相关资源
        最近更新 更多