gen*_*sis 12 mysql full-text-search
我不明白这个。
我有一个包含这些索引的表
PRIMARY post_id
INDEX topic_id
FULLTEXT post_text
Run Code Online (Sandbox Code Playgroud)
表有(仅)346 000 行。我正在尝试执行 2 个查询。
SELECT post_id
FROM phpbb_posts
WHERE topic_id = 144017
AND post_id != 155352
AND MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar')
Run Code Online (Sandbox Code Playgroud)
需要 4.05 秒,而
SELECT post_id
FROM phpbb_posts
WHERE topic_id=144017
AND post_id != 155352
AND post_text LIKE ('%http://rapidshare.com/files/5494794/photo.rar%')
Run Code Online (Sandbox Code Playgroud)
需要 0.027 秒。
EXPLAIN 显示唯一的区别在于可能的键(fulltext包含 post_text,LIKE不包含)
这真的很奇怪。
这背后是什么?后台发生了什么?LIKE不使用索引时怎么会这么快,而使用它的索引时 FULLTEXT怎么会这么慢?
实际上现在大约需要 0.5 秒,也许表被锁定了,但是,当我打开分析时,它显示 FULLTEXT INITIALIZATION 花了 0.2 秒。这是怎么回事?
我可以LIKE每秒 10 倍的速度查询我的表格,而全文只有 2 倍
惊喜!
mysql> SELECT post_id FROM phpbb_posts WHERE post_id != 2 AND topic_id = 6 AND MATCH(post_text) AGAINST ('rapidshare.com');
Empty set (0.04 sec)
Run Code Online (Sandbox Code Playgroud)
所以我问,这怎么可能?
此外,
SELECT count(*) FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com')
Run Code Online (Sandbox Code Playgroud)
真的很慢。可以全文任意破吗?
我勒个去?
SELECT forum_id, post_id, topic_id, post_text FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;
Run Code Online (Sandbox Code Playgroud)
需要 0.27s 而
SELECT count(*) FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;
Run Code Online (Sandbox Code Playgroud)
需要30多秒!这里出了什么问题?
我认为问题可能源于 FULLTEXT 索引本身的存在。
每次有涉及 FULLTEXT 索引的查询时,MySQL 查询优化器都会将该查询打造成全表扫描。多年来我已经看到了这一点。我还写了一篇关于全文索引中最琐碎行为的早期文章。
您可能需要做两件事:
这是您的原始查询
SELECT post_id
FROM phpbb_posts
WHERE topic_id = 144017
AND post_id != 155352
AND MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar')
Run Code Online (Sandbox Code Playgroud)
您将需要像这样重构查询:
SELECT subqueryA.post_id
FROM
(
SELECT post_id FROM phpbb_posts
WHERE topic_id = 144017
AND post_id != 155352
) subqueryA
INNER JOIN
(
SELECT post_id FROM phpbb_posts
WHERE MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar')
) subqueryB
USING (post_id);
Run Code Online (Sandbox Code Playgroud)
您将需要一个索引来支持subqueryA。您已经在 上有一个索引topic_id。您需要按如下方式替换它:
ALTER TABLE phpbb_posts ADD INDEX topic_post_ndx (topic_id,post_id);
ALTER TABLE phpbb_posts DROP INDEX topic_id;
Run Code Online (Sandbox Code Playgroud)
试一试 !!!
首先尝试这个
SELECT post_id FROM
(
SELECT * FROM phpbb_posts
WHERE topic_id = 144017
AND post_id != 155352
) A;
Run Code Online (Sandbox Code Playgroud)
如果它运行得很快并且返回少量行,那么尝试这个嵌套子查询:
SELECT post_id FROM
(
SELECT * FROM phpbb_posts
WHERE topic_id = 144017
AND post_id != 155352
) A
WHERE MATCH(post_text) AGAINST('http://rapidshare.com/files/5494794/photo.rar');
Run Code Online (Sandbox Code Playgroud)
比较一下这个的运行时间:
SELECT count(*) FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;
Run Code Online (Sandbox Code Playgroud)
有了这个
SELECT count(*) FROM phpbb_posts WHERE 1 = 1;
Run Code Online (Sandbox Code Playgroud)
如果运行时间相同,则 MATCH 子句将在每一行上执行。正如我之前提到的,使用 FULLTEXT 索引往往会抵消 MySQL 查询优化器尝试和贡献的任何好处。