简体   繁体   English

与“=”运算符相比,SQLite“LIKE”运算符非常慢

[英]SQLite "LIKE" operator is very slow compared to the "=" operator

When I am using the LIKE operator in SQLite, it is very slow compared to when I use the = instead.当我在 SQLite 中使用LIKE运算符时,与使用=时相比,速度非常慢。 It takes about 14ms with the = operator, but when I use LIKE , it takes about 440ms.使用=运算符大约需要 14 毫秒,但是当我使用LIKE ,大约需要 440 毫秒。 I am testing this with DB Browser for SQLite .我正在使用DB Browser for SQLite对此进行测试。 Here is the query that works fast:这是运行速度很快的查询:

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

The slows down when I change当我改变时变慢

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')

to

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')

I need to do this so that I can use wildcards eg我需要这样做,以便我可以使用通配符,例如

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%')

Here is a link to the database itself: https://www.mediafire.com/file/hyuymc84022gzq7/dictionary.db/file这是数据库本身的链接: https : //www.mediafire.com/file/hyuymc84022gzq7/dictionary.db/file

Thanks谢谢

Try putting a full-text index on the columns you are using.尝试在您使用的列上放置全文索引。

see Full Text Indexing全文索引

Create Catalog创建目录

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

Create Index创建索引

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

Note This is more of a convenience, but see if your collation is case insensitive so that for example an 'a' = 'A'.注意这更方便,但请查看您的排序规则是否不区分大小写,例如'a' = 'A'。 Normally the collation will have a ci_utf8 for example (ci = case insensitive).通常排序规则会有一个 ci_utf8 例如(ci = 不区分大小写)。 I do this for the user and programmer convenience.我这样做是为了用户和程序员的方便。

FTS? FTS?

Using DB Browser for sqlite on Win 10.在 Win 10 上使用 DB Browser for sqlite。

  • "fast" query returns 25 rows in 84ms “快速”查询在 84 毫秒内返回 25 行
  • "slow" query (using LIKE "example%" ) returns 33 rows in 1025ms “慢”查询(使用LIKE "example%" )在 1025 毫秒内返回 33 行

Created fts4 tables like so:像这样创建 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;

It took 7390ms, database grew from 70,296KB to 110,708KB.耗时 7390 毫秒,数据库从 70,296KB 增长到 110,708KB。

Modified the WHERE like so:像这样修改了 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')

Query returned 33 rows in 60ms.查询在 60 毫秒内返回了 33 行。

I cannot test or analyze how FTS will work on the reading_element column, but perhapse the approach shows promise.我无法测试或分析 FTS 如何在reading_element列上工作,但reading_element该方法显示出希望。

I wonder if using HAVING would speed your query:我想知道使用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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM