Pencarian teks lengkap menghasilkan banyak waktu yang dihabiskan dalam 'inisialisasi FULLTEXT'

12

Saat ini saya mencoba menjalankan beberapa query terhadap data dump komentar Stack Overflow. Seperti apa skema ini:

CREATE TABLE `socomments` (
  `Id` int(11) NOT NULL,
  `PostId` int(11) NOT NULL,
  `Score` int(11) DEFAULT NULL,
  `Text` varchar(600) NOT NULL,
  `CreationDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `UserId` int(11) NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `idx_socomments_PostId` (`PostId`),
  KEY `CreationDate` (`CreationDate`),
  FULLTEXT KEY `Text` (`Text`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

Saya menjalankan kueri ini terhadap tabel, dan berjalan sangat lambat (Memang memiliki 29 juta baris, tetapi memiliki indeks Teks Lengkap):

SELECT *
FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)

Jadi saya membuat profilnya, hasilnya adalah:

|| Status                     || Duration ||
|| starting                   || 0.000058 ||
|| checking permissions       || 0.000006 ||
|| Opening tables             || 0.000014 ||
|| init                       || 0.000019 ||
|| System lock                || 0.000006 ||
|| optimizing                 || 0.000007 ||
|| statistics                 || 0.000013 ||
|| preparing                  || 0.000005 ||
|| FULLTEXT initialization    || 207.1112 ||
|| executing                  || 0.000009 ||
|| Sending data               || 0.000856 ||
|| end                        || 0.000004 ||
|| query end                  || 0.000004 ||
|| closing tables             || 0.000006 ||
|| freeing items              || 0.000059 ||
|| logging slow query         || 0.000037 ||
|| cleaning up                || 0.000046 ||

Seperti yang Anda lihat, ini menghabiskan waktu yang lama dalam inisialisasi FULLTEXT. Apakah ini normal? Jika tidak, bagaimana saya memperbaikinya?

hichris123
sumber
Ide: Bangun tabel ke-2 tempat Anda meletakkan setiap 1.000 komentar dalam satu bidang teks. Sekarang Anda mencari pertama di tabel kedua ini dan Anda mendapatkan contoh id_group 2dan id_group 23. Dengan ini pencarian Anda di dalam tabel utama Anda dan batasi permintaan Anda untuk rentang id 2.000 hingga 2.999 dan 23.000 hingga 23.999. Tentu saja yang ke-2 akan menghasilkan lebih banyak hasil sesuai kebutuhan ketika Anda menggabungkan semua komentar membuat kombinasi kata kunci baru, tetapi akhirnya akan mempercepat semuanya. Tentu saja itu menggandakan penggunaan ruang disk. Komentar baru harus CONCAT'ed ke tabel grup.
mgutt

Jawaban:

5

Yang lain menganggap ini situasi yang merepotkan

Karena Dokumentasi MySQL sangat singkat tentang status utas ini

Inisialisasi FULLTEXT

Server sedang bersiap untuk melakukan pencarian teks lengkap dalam bahasa alami.

satu-satunya jalan Anda adalah membuat persiapan dengan lebih sedikit data. Bagaimana?

SARAN # 1

Lihatlah permintaan Anda lagi. Itu memilih semua kolom. Saya akan menolak permintaan untuk mengumpulkan hanya kolom id dari socomments. Kemudian, gabungkan id yang diambil kembali ke socommentstabel.

SELECT B.* FROM
(SELECT id FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)) A
LEFT JOIN socomments B USING (id);

Ini mungkin menghasilkan rencana EXPLAIN yang lebih buruk tetapi saya pikir profiling akan berubah menjadi lebih baik. Ide dasarnya adalah: Jika Anda memiliki Pencarian FULLTEXT yang agresif, buatlah mengumpulkan data dengan jumlah paling sedikit selama FULLTEXT initializationfase itu, sehingga mengurangi waktu.

Saya telah merekomendasikan ini berkali-kali sebelumnya

SARAN # 2

Pastikan Anda mengatur opsi FULLTEXT berbasis InnoDB, bukan yang untuk MyISAM. Dua opsi yang harus Anda perhatikan adalah

Pikirkan sejenak. Bidang teks adalah VARCHAR (600). Katakanlah rata-rata adalah 300 byte. Anda memiliki 29.000.000.000 dari mereka. Itu akan menjadi sedikit 8GB. Mungkin meningkatkan innodb_ft_cache_size dan innodb_ft_total_cache_size juga dapat membantu.

Pastikan Anda memiliki cukup RAM untuk buffer InnoDB FULLTEXT yang lebih besar.

COBALAH !!!

RolandoMySQLDBA
sumber
Mencoba kedua saran itu, itu membawa waktu turun sekitar 10 detik, hingga 200 detik. Yang aneh adalah bahwa buffer pool hanya pada utilisasi 9% ...
hichris123
Coba letakkan tanda tambah di dalam bagian TERHADAP: SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);dan lihat apakah itu membuat perbedaan.
RolandoMySQLDBA
Alasan saya menyarankan tanda tambah? Doc ( dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html ) mengatakan A leading or trailing plus sign indicates that this word must be present in each row that is returned. InnoDB only supports leading plus signs.Dalam kasus khusus Anda, frasa yang tepat fixed the postharus ada.
RolandoMySQLDBA
Hasil yang sama. Sedikit lebih cepat & lebih lambat, jadi mungkin hanya karena perbedaan menit ketika dieksekusi.
hichris123
5

Jika Anda menggunakan indeks InnoDB FULLTEXT, kueri akan sering menggantung dalam keadaan "inisialisasi FULLTEXT" jika Anda menanyakan tabel yang memiliki banyak baris yang dihapus. Dalam implementasi FULLTEXT InnoDB, baris yang dihapus tidak dipangkas sampai operasi OPTIMIZE berikutnya dijalankan terhadap tabel yang terpengaruh. Lihat: https://dev.mysql.com/doc/refman/5.6/id/innodb-fulltext-index.html

Untuk menghapus entri indeks teks lengkap untuk catatan yang dihapus, Anda harus menjalankan OPTIMIZE TABLE pada tabel yang diindeks dengan innodb_optimize_fulltext_only = ON untuk membangun kembali indeks teks lengkap.

Seseorang juga dapat memeriksa jumlah catatan yang dihapus tetapi tidak dibersihkan dengan menanyakan informasi_schema.innodb_ft_deleted

Untuk mengatasi ini, orang harus menjalankan TABEL OPTIMASI secara teratur terhadap tabel dengan indeks InnoDB FULLTEXT.

Tyler
sumber
Saya mendapatkan logika tentang ini, tetapi dapatkah Anda memverifikasi itu innodb_optimize_fulltext_only=1dan sebuah OPTIMIZEtabel benar-benar menangani baris yang dihapus "dalam menunggu"? dba.stackexchange.com/questions/174486/…
Riedsio
0

Indeks teks lengkap di MySQL tidak dirancang untuk mendukung data dalam jumlah besar sehingga kecepatan pencarian menurun cukup cepat saat dataset Anda tumbuh dewasa. Salah satu solusinya adalah dengan menggunakan mesin pencarian teks lengkap eksternal seperti Solr atau Sphinx yang telah meningkatkan fungsionalitas pencarian (pencarian relevansi dan dukungan pencarian frasa, aspek bawaan, snippet, dll.) Sintaks kueri yang diperluas dan kecepatan lebih cepat pada pertengahan hingga set data besar.

Solr didasarkan pada platform Java jadi jika Anda menjalankan aplikasi berbasis Java akan menjadi pilihan alami untuk Anda, Sphinx ditulis pada C ++ dan bertindak sebagai daemon dengan cara yang sama seperti MySQL. Segera setelah Anda memberi makan mesin eksternal dengan data yang ingin Anda cari, Anda juga dapat memindahkan beberapa pertanyaan dari MySQL. Saya tidak dapat memberi tahu Anda mesin mana yang lebih baik dalam kasus Anda, saya menggunakan sebagian besar Sphinx dan di sini adalah contoh penggunaan: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

vfedorkov
sumber