Mengapa LIKE lebih dari 4x lebih cepat dari MATCH ... MELAWAN indeks FULLTEXT di MySQL?


12

Saya tidak mendapatkan ini.

Saya punya tabel dengan indeks ini

PRIMARY     post_id
INDEX       topic_id
FULLTEXT    post_text

Tabel memiliki (hanya) 346.000 baris. Saya mencoba melakukan 2 pertanyaan.

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

membutuhkan waktu 4,05 detik

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

membutuhkan waktu 0,027 detik.

EXPLAIN menunjukkan bahwa satu-satunya perbedaan adalah dalam kemungkinan_kunci ( fulltextsudah termasuk post_text, LIKEtidak)

Itu sangat aneh.

Ada apa di balik ini? Apa yang terjadi di latar belakang? Bagaimana bisa LIKEbegitu cepat ketika tidak menggunakan indeks dan FULLTEXT sangat lambat saat menggunakan indeksnya?

UPDATE1:

Sebenarnya sekarang ini membutuhkan waktu sekitar 0,5 detik, mungkin meja dikunci, tetapi tetap saja, ketika saya menghidupkan profil, ini menunjukkan bahwa INISIIALISASI FULLTEXT memerlukan waktu 0,2 detik. Ada apa?

Saya dapat meminta tabel saya dengan LIKE10x per detik, dengan teks lengkap hanya 2x

UPDATE2:

Mengherankan!

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)

jadi saya bertanya, bagaimana ini mungkin?

Selain itu,

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

sangat lambat. Bisakah teks lengkap rusak?

UPDATE3:

Apa apaan?

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

Dibutuhkan waktu 0,27 detik

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

membutuhkan waktu lebih dari 30 detik! Apa yang salah di sini?


Apakah waktu respons antara keduanya konsisten selama beberapa kali berjalan? Saya tergoda untuk berpikir bahwa cache disk bisa digunakan ketika tes "lambat" pertama memuat semua data yang diperlukan ke dalam ram sehingga permintaan "cepat" kedua adalah, sangat cepat.
atxdba

Kueri pengujian hanya dengan SQL_NO_CACHE .
mgutt

Ini pertanyaan / jawaban yang cukup lama. Adakah kemajuan dari mysql / mariadb sejak masa itu?
Roman Susi

1
Perhatian: Waktu tanya jawab ini menyiratkan bahwa ini hanya berbicara tentang MyISAM. Penerapannya untuk InnoDB dipertanyakan.
Rick James

@RomanSusi - Apakah Anda ingin memulai pertanyaan baru yang ditujukan untuk InnoDB?
Rick James

Jawaban:


2

Saya pikir masalahnya mungkin berasal dari keberadaan indeks FULLTEXT itu sendiri.

Setiap kali ada kueri yang melibatkan indeks FULLTEXT, Pengoptimal Kueri MySQL cenderung mendorong kueri ke dalam pemindaian tabel penuh. Saya telah melihat ini selama bertahun-tahun. Saya juga menulis posting sebelumnya tentang perilaku paling sepele ini dalam indeks FULLTEXT .

Anda mungkin perlu melakukan dua hal:

  1. refactor kueri sehingga indeks FULLTEXT tidak membuat MySQL Query Optimizer menjadi bingung
  2. Tambahkan indeks tambahan yang akan dengan benar mendukung permintaan refactored

REFACTOR QUERY THE

Ini pertanyaan asli Anda

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

Anda harus memperbarui permintaan seperti ini:

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

BUAT INDEKS BARU

Anda akan memerlukan indeks untuk mendukung subqueryA. Anda sudah memiliki indeks topic_id. Anda perlu menggantinya sebagai berikut:

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

Cobalah !!!

UPDATE 2012-03-19 13:08 EDT

Coba yang ini dulu

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

Jika ini berjalan cepat dan mengembalikan sejumlah kecil baris, cobalah subquery bersarang ini:

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

UPDATE 2012-03-19 13:11 EDT

Bandingkan waktu berjalan ini:

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

dengan ini

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

Jika ada waktu berjalan yang sama, maka klausa MATCH dieksekusi pada setiap baris. Seperti yang saya sebutkan sebelumnya, menggunakan indeks FULLTEXT cenderung membatalkan manfaat apa pun yang dicoba dan dikontribusikan oleh Pengoptimal Permintaan MySQL.


Jadi Anda ingin mengatakan bahwa permintaan saya benar-benar memindai seluruh tabel karena topic_id dan post_idmembingungkannya? Mengapa kueri LIKE berfungsi bahkan tanpa indeks pada kolom ini (topic_id, post_id)? Mengapa MYSQL tidak hanya memilih dengan cerdas topic_id = 144017 AND post_id != 155352dan kemudian hanya menelusuri melalui hasil ini? Dan bagaimana jika 100k baris menyertakan string pencarian teks lengkap saya post_text? Bukankah itu akan memilih semuanya?
genesis

Sebenarnya saya lebih bingung lagi. SEPERTI '% text%' juga tidak menggunakan indeks, itu berarti memindai seluruh tabel, jadi mengapa begitu cepat?
genesis

Silakan lihat UPDATE saya , saya pikir Anda akan menyelesaikannya dengan sangat cepat. Saya akan memberi Anda perwakilan saya jika Anda menyelesaikannya.
genesis

Membalas pembaruan kedua Anda. Kueri kedua berjalan dalam waktu kurang dari 0,01 ms, yang pertama tidak selesai. Mengapa Anda mengatakan "Jika ada waktu berjalan yang sama, maka klausa MATCH dieksekusi di setiap baris." ? Bukankah itu kebalikan dari yang seharusnya? Jika Anda melihat di sini , Anda akan melihat saya bukan satu-satunya dengan masalah ini
genesis

Membalas pembaruan pertama Anda. Kueri pertama berjalan dalam 0,01ms, 0 baris, yang kedua kembali "Tidak dapat menemukan indeks FULLTEXT yang cocok dengan daftar kolom". Namun, kueri Anda dengan 2 subkueri berfungsi dengan sempurna!
genesis
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.