全文索引提高速度,SQL 数据库设计
FULLTEXT Indexes for speed, SQL database design
我有一千万条记录。 MySQL 数据库如下所示:
tagline: varchar(255)
location: varchar(80)
experience: text (normally about 600 characters)
country varchar(50)
以前,我正在执行这样的查询,这导致了完整的 table 扫描,这花费了太长时间:
SELECT COUNT(*) FROM `mytable` WHERE
`tagline` LIKE '%sales%'
AND `location` LIKE '%texas%'
AND `experience` LIKE '%software%'
这里的人告诉我应该对每个字段应用全文索引。他们告诉我应该执行这样的查询:
SELECT COUNT(*) FROM `mytable` WHERE
MATCH(tagline) AGAINST("sales")
AND MATCH(location) AGAINST("texas")
AND MATCH(experience) AGAINST("software")
我只想确认一下:
(a) 结果应该是一样的
(b)速度会更快
(c) 唯一的缺点是数据库的大小增加以及我的系统在每个字段上实现 FULLTEXT 索引所花费的时间。
请不要指责我太具体。仅以我的设置为例。任何想要搜索功能并拥有大量文本数据的人都会从回复中受益。
正如我在上面的评论中提到的,如果您分别为三列中的每一列编制索引,则 MySQL 查询必须为每个 table 引用选择一个索引。它不能在同一查询中使用所有三个索引,除非您使用不同的 table 引用。
您应该为所有三列创建一个全文索引:
ALTER TABLE mytable ADD FULLTEXT INDEX(tagline, location, experience);
然后用一个谓词搜索:
SELECT COUNT(*)
FROM `mytable`
WHERE MATCH(tagline, location, experience)
AGAINST("+sales +texas +software" IN BOOLEAN MODE);
但这失去了在每列中找到哪个关键字的关联。然后您可以应用 old-school LIKE
条件来优化搜索,这些条件只需要检查与全文搜索匹配的行。
SELECT COUNT(*)
FROM `mytable`
WHERE MATCH(tagline, location, experience)
AGAINST("+sales +texas +software" IN BOOLEAN MODE)
AND tagline LIKE '%sales%'
AND location LIKE '%texas%'
AND experience LIKE '%software%';
代价高昂的部分是当查询必须执行 table-scan 以检查数百万行时。如果您使用全文索引将候选匹配项缩小到几行,则使用 LIKE
对一小部分行进行的额外字符串比较可能不会太昂贵。
回复您的评论:
这是我在 运行 EXPLAIN 测试 table 中得到的结果:
mysql> create table mytable (
id serial primary key,
tagline text,
location text,
experience text,
fulltext index(tagline, location, experience)
);
mysql> explain SELECT COUNT(*)
-> FROM `mytable`
-> WHERE MATCH(tagline, location, experience)
-> AGAINST("+sales +texas +software" IN BOOLEAN MODE)
-> AND tagline LIKE '%sales%'
-> AND location LIKE '%texas%'
-> AND experience LIKE '%software%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mytable
partitions: NULL
type: fulltext
possible_keys: tagline
key: tagline
key_len: 0
ref: const
rows: 1
filtered: 100.00
Extra: Using where; Ft_hints: no_ranking
type: fulltext
表示将使用全文索引。
我有一千万条记录。 MySQL 数据库如下所示:
tagline: varchar(255)
location: varchar(80)
experience: text (normally about 600 characters)
country varchar(50)
以前,我正在执行这样的查询,这导致了完整的 table 扫描,这花费了太长时间:
SELECT COUNT(*) FROM `mytable` WHERE
`tagline` LIKE '%sales%'
AND `location` LIKE '%texas%'
AND `experience` LIKE '%software%'
这里的人告诉我应该对每个字段应用全文索引。他们告诉我应该执行这样的查询:
SELECT COUNT(*) FROM `mytable` WHERE
MATCH(tagline) AGAINST("sales")
AND MATCH(location) AGAINST("texas")
AND MATCH(experience) AGAINST("software")
我只想确认一下:
(a) 结果应该是一样的
(b)速度会更快
(c) 唯一的缺点是数据库的大小增加以及我的系统在每个字段上实现 FULLTEXT 索引所花费的时间。
请不要指责我太具体。仅以我的设置为例。任何想要搜索功能并拥有大量文本数据的人都会从回复中受益。
正如我在上面的评论中提到的,如果您分别为三列中的每一列编制索引,则 MySQL 查询必须为每个 table 引用选择一个索引。它不能在同一查询中使用所有三个索引,除非您使用不同的 table 引用。
您应该为所有三列创建一个全文索引:
ALTER TABLE mytable ADD FULLTEXT INDEX(tagline, location, experience);
然后用一个谓词搜索:
SELECT COUNT(*)
FROM `mytable`
WHERE MATCH(tagline, location, experience)
AGAINST("+sales +texas +software" IN BOOLEAN MODE);
但这失去了在每列中找到哪个关键字的关联。然后您可以应用 old-school LIKE
条件来优化搜索,这些条件只需要检查与全文搜索匹配的行。
SELECT COUNT(*)
FROM `mytable`
WHERE MATCH(tagline, location, experience)
AGAINST("+sales +texas +software" IN BOOLEAN MODE)
AND tagline LIKE '%sales%'
AND location LIKE '%texas%'
AND experience LIKE '%software%';
代价高昂的部分是当查询必须执行 table-scan 以检查数百万行时。如果您使用全文索引将候选匹配项缩小到几行,则使用 LIKE
对一小部分行进行的额外字符串比较可能不会太昂贵。
回复您的评论:
这是我在 运行 EXPLAIN 测试 table 中得到的结果:
mysql> create table mytable (
id serial primary key,
tagline text,
location text,
experience text,
fulltext index(tagline, location, experience)
);
mysql> explain SELECT COUNT(*)
-> FROM `mytable`
-> WHERE MATCH(tagline, location, experience)
-> AGAINST("+sales +texas +software" IN BOOLEAN MODE)
-> AND tagline LIKE '%sales%'
-> AND location LIKE '%texas%'
-> AND experience LIKE '%software%'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mytable
partitions: NULL
type: fulltext
possible_keys: tagline
key: tagline
key_len: 0
ref: const
rows: 1
filtered: 100.00
Extra: Using where; Ft_hints: no_ranking
type: fulltext
表示将使用全文索引。