在 MySQL 中搜索 varchar 列的最快方法
Fastest way to search a varchar column in MySQL
我想执行一个书店的搜索查询。我使用 MySQL 并且我有一个 varchar 列,其中包含名称、作者或其他详细信息,例如 The Tragedy of Hamlet, Prince of Denmark, by William Shakespeare
,我想搜索 shakespeare tragedy
或 denmark tragedy
以获取图书列表将它们放在一栏中。
我有三个查询来实现这个,但我想知道它们的性能。
喜欢 %%
我的第一种方法是将搜索文本拆分为单词并根据单词计数创建动态命令:
SELECT * FROM books
WHERE name LIKE '%shakespeare%'
AND name LIKE '%tragedy%'
但是有人告诉我 like
是一个慢运算符,特别是有两个 % 因为它不能使用索引。
TAG table和关系划分
我的第二种方法是使用另一个 table,其中包含如下标签:
-------------------------
| book_id | tag |
|-----------------------|
| 1 | Tragedy |
| 1 | Hamlet |
| 1 | Prince |
| 1 | Denmark |
| 1 | William |
| 1 | Shakespeare |
-------------------------
并创建动态除法命令:
SELECT DISTINCT book_id FROM booktag AS b1
WHERE ((SELECT 'shakespeare' as tag UNION SELECT 'tragedy' as tag)
EXCEPT
SELECT tag FROM booktag AS b2 WHERE b1.book_id = b2.book_id) IS NULL
但有人告诉我 relational division
也太慢了。
REGEXP
我的第三种方式是使用正则表达式:
SELECT * FROM books
WHERE name REGEXP '(?=.*shakespeare)(?=.*tragedy)'
但是有人告诉我它比LIKE
慢
请帮我决定哪种方式更快?
当然使用 LIKE
这是一个 built-in 操作数,比正则表达式更优化。但这里有一点很重要,你不能将这两个配方放在一起比较,因为 LIKE
用于向字符串添加通配符,而正则表达式用于根据可能非常复杂的模式匹配字符串。
无论如何,我想到的实现此目标的最佳方法是以下方法之一:
- 在已正确索引的列上使用
LIKE
。1
- 使用一些优化的搜索技术,例如 elastic search。
- 实施多线程算法 2,它对 IO 任务执行得非常好。对于这个,您可以使用一些技巧,例如定义偏移量并在线程之间划分 table。
另请参阅本文 https://technet.microsoft.com/en-us/library/aa175787%28v=sql.80%29.aspx
1. 您应该注意在 columns.read 上放置索引的方式以获得更多信息 and this post http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning
2.Read 此答案了解更多信息 Multi Thread in SQL?
我想执行一个书店的搜索查询。我使用 MySQL 并且我有一个 varchar 列,其中包含名称、作者或其他详细信息,例如 The Tragedy of Hamlet, Prince of Denmark, by William Shakespeare
,我想搜索 shakespeare tragedy
或 denmark tragedy
以获取图书列表将它们放在一栏中。
我有三个查询来实现这个,但我想知道它们的性能。
喜欢 %%
我的第一种方法是将搜索文本拆分为单词并根据单词计数创建动态命令:
SELECT * FROM books
WHERE name LIKE '%shakespeare%'
AND name LIKE '%tragedy%'
但是有人告诉我 like
是一个慢运算符,特别是有两个 % 因为它不能使用索引。
TAG table和关系划分
我的第二种方法是使用另一个 table,其中包含如下标签:
-------------------------
| book_id | tag |
|-----------------------|
| 1 | Tragedy |
| 1 | Hamlet |
| 1 | Prince |
| 1 | Denmark |
| 1 | William |
| 1 | Shakespeare |
-------------------------
并创建动态除法命令:
SELECT DISTINCT book_id FROM booktag AS b1
WHERE ((SELECT 'shakespeare' as tag UNION SELECT 'tragedy' as tag)
EXCEPT
SELECT tag FROM booktag AS b2 WHERE b1.book_id = b2.book_id) IS NULL
但有人告诉我 relational division
也太慢了。
REGEXP
我的第三种方式是使用正则表达式:
SELECT * FROM books
WHERE name REGEXP '(?=.*shakespeare)(?=.*tragedy)'
但是有人告诉我它比LIKE
请帮我决定哪种方式更快?
当然使用 LIKE
这是一个 built-in 操作数,比正则表达式更优化。但这里有一点很重要,你不能将这两个配方放在一起比较,因为 LIKE
用于向字符串添加通配符,而正则表达式用于根据可能非常复杂的模式匹配字符串。
无论如何,我想到的实现此目标的最佳方法是以下方法之一:
- 在已正确索引的列上使用
LIKE
。1 - 使用一些优化的搜索技术,例如 elastic search。
- 实施多线程算法 2,它对 IO 任务执行得非常好。对于这个,您可以使用一些技巧,例如定义偏移量并在线程之间划分 table。
另请参阅本文 https://technet.microsoft.com/en-us/library/aa175787%28v=sql.80%29.aspx
1. 您应该注意在 columns.read 上放置索引的方式以获得更多信息 and this post http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning
2.Read 此答案了解更多信息 Multi Thread in SQL?