it-swarm-eu.dev

Proč je LIKE více než 4x rychlejší než MATCH ... PROTI FULLTEXT indexu v MySQL?

Nechápu to.

Mám tabulku s těmito indexy

PRIMARY     post_id
INDEX       topic_id
FULLTEXT    post_text

Tabulka obsahuje (pouze) 346 000 řádků. Snažím se provést 2 dotazy.

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

trvá 4,05 sekund

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

trvá 0,027 sekundy.

EXPLAIN ukazuje, že jediným rozdílem je možný_keys (fulltext obsahuje post_text, LIKE ne)

To je opravdu divné.

Co je za tím? Co se děje v pozadí? Jak může být LIKE tak rychlý, když nepoužíváme index a FULLTEXT tak pomalý, když používám jeho index?

UPDATE1:

Ve skutečnosti to nyní trvá asi 0,5 sekundy, možná byl stůl zamčený, ale přesto, když zapnu profilování, ukazuje se, že FULLTEXT INITIALIZATION trvalo 0,2 sekundy. Co se děje?

Mohu dotazovat svou tabulku s LIKE 10x za sekundu, s fulltextem pouze 2x

UPDATE2:

Překvapení!

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)

tak se ptám, jak je to možné?

Dodatečně,

SELECT count(*) FROM phpbb_posts WHERE MATCH(post_text) AGAINST ('rapidshare.com')

je opravdu pomalý. Může být fulltext rozbitý?

UPDATE3:

Co to k sakru?

SELECT forum_id, post_id, topic_id, post_text  FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

trvá 0,27 s

SELECT count(*) FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

trvá déle než 30 sekund! Co se tady děje?

12
genesis

Myslím, že problém může pramenit z přítomnosti samotného indexu FULLTEXT.

Pokaždé, když existuje dotaz týkající se indexu FULLTEXT, nástroj MySQL Query Optimizer inklinuje dotaz na dotaz do skenování v plné tabulce. Viděl jsem to v průběhu let. Také jsem psal dřívější příspěvek o tomto nejmilnějším chování v indexech FULLTEXT .

Možná budete muset udělat dvě věci:

  1. změňte dotaz tak, aby index FULLTEXT nevrhal Optimalizátor dotazů MySQL do stavu záměny
  2. Přidejte další index, který bude správně podporovat refactored dotaz

REFACTOR DOTAZ

Zde je váš původní dotaz

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

Dotaz budete muset změnit takto:

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

VYTVOŘTE NOVÝ INDEX

Pro podporu subqueryA budete potřebovat index. Již máte index na topic_id. Musíte ji nahradit následovně:

ALTER TABLE phpbb_posts ADD INDEX topic_post_ndx (topic_id,post_id);
ALTER TABLE phpbb_posts DROP INDEX topic_id;

Pokusit se !!!

AKTUALIZACE 2012-03-19 13:08 EDT

Zkuste to první

SELECT post_id FROM
(
    SELECT * FROM phpbb_posts
    WHERE topic_id = 144017
    AND post_id != 155352
) A;

Pokud to běží rychle a vrací malý počet řádků, zkuste tento vnořený poddotaz:

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

AKTUALIZACE 2012-03-19 13:11 EDT

Porovnejte provozní dobu:

SELECT count(*) FROM phpbb_posts  WHERE MATCH(post_text) AGAINST ('rapidshare.com') LIMIT 0, 30;

s tím

SELECT count(*) FROM phpbb_posts WHERE 1 = 1;

Pokud je doba běhu stejná, pak se klauzule MATCH provádí na každém řádku. Jak jsem zmínil dříve, použití indexů FULLTEXT má tendenci anulovat všechny výhody, o které se pokoušel a přispěl Optimalizátor dotazů MySQL.

2
RolandoMySQLDBA