Tam metin arama, 'FULLTEXT başlatma' için çok fazla zaman harcanmasına neden olur


12

Şu anda Stack Overflow'ın yorumlarının bir veri dökümüne karşı bazı sorgular çalıştırmaya çalışıyorum. Şema şöyle görünüyor:

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

Bu sorguyu tablo karşı çalıştırdı ve inanılmaz derecede yavaş koştu (29 milyon satır var, ama bir tam metin dizini vardır):

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

Bu yüzden profilli, sonuçları:

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

Gördüğünüz gibi, FULLTEXT başlatmasında uzun zaman geçiriyor. Bu normal mi? Değilse, nasıl düzeltebilirim?


Fikir: Her 1.000 yorumu bir metin alanına koyduğunuz 2. bir tablo oluşturun. Şimdi ilk önce bu ikinci tabloda arama yaparsınız id_group 2ve örneğin ve id_group 23. Bununla, ana tablonuzun içinde aramanız ve sorgunuzu 2.000 ila 2.999 ve 23.000 ila 23.999 kimlik aralıklarıyla sınırlandırın. Tabii ki, 2. yeni anahtar kelime kombinasyonları oluşturan tüm yorumları karıştırdıkça daha fazla sonuç elde edeceksiniz, ancak son olarak her şeyi hızlandırmalıdır. Tabii ki disk alanı kullanımını iki katına çıkarıyor. Yeni yorumlar grup tablosuna CONCAT'lanmalıdır .
mgutt

Yanıtlar:


5

Diğerleri bunu zahmetli bir durum olarak gördüler

Yana MySQL Dokümantasyon Konuyu durumuna çok veciz olduğu

FULLTEXT başlatma

Sunucu, doğal dilde tam metin araması yapmaya hazırlanıyor.

tek başvurunuz daha az veriyle hazırlık yapmak olacaktır. Nasıl ?

ÖNERİ # 1

Sorgunuza tekrar bakın. Tüm sütunları seçiyor. Ben sadece kimlik sütunları toplamak için sorgu refactor istiyorsunuz socomments. Ardından, geri getirilen kimlikleri tekrar socommentsmasaya ekleyin .

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

Bu daha çirkin bir EXPLAIN planı üretebilir ama bence profilleme daha iyi olacak. Temel fikir şudur: Agresif bir FULLTEXT Aramanız varsa, bu FULLTEXT initializationaşamada en az miktarda veri toplamasını sağlayın , böylece zamanı azaltın.

Bunu daha önce birçok kez tavsiye ettim

ÖNERİ # 2

Lütfen MyISAM için olanları değil, InnoDB tabanlı FULLTEXT seçeneklerini ayarladığınızdan emin olun. Endişelenmeniz gereken iki seçenek

Bir an düşünün. Metin alanı VARCHAR (600) şeklindedir. Diyelim ki ortalama 300 bayt. Bunların 29.000.000 milyonu var. Bu 8GB biraz olurdu. Belki artan innodb_ft_cache_size ve innodb_ft_total_cache_size de yardımcı olabilir.

Daha büyük InnoDB FULLTEXT tamponları için yeterli RAM'e sahip olduğunuzdan emin olun.

BİR ŞANS VER !!!


Her iki öneriyi de denedi, zamanı 10 saniyeye 200 saniyeye indirdi. Garip şey, tampon havuzunun sadece% 9 kullanımda olması ...
hichris123

AGAINST kısmına bir artı işareti koymayı deneyin: SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);ve bunun bir fark yaratıp yaratmadığına bakın.
RolandoMySQLDBA

Artı işareti önermemin sebebi nedir? Doc ( dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html ) diyor 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.Özel durumunuzda, tam ifade fixed the postolmalıdır.
RolandoMySQLDBA

Aynı sonuçlar. Biraz daha hızlı ve daha yavaş, bu yüzden muhtemelen ne zaman yürütüldüğündeki küçük farklılıklar nedeniyle.
14:19:19

5

InnoDB FULLTEXT dizinleri kullanıyorsanız, çok sayıda silinmiş satır içeren bir tabloyu sorgulamak için sorgular genellikle "FULLTEXT başlatma" durumunda askıda kalır. InnoDB'nin FULLTEXT uygulamasında, etkilenen tabloya karşı bir OPTIMIZE işlemi yürütülene kadar silinen satırlar budanmaz. Bkz. Https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

Silinen kayıtların tam metin dizini girdilerini kaldırmak için, tam metin dizinini yeniden oluşturmak üzere dizinlenmiş tabloda innodb_optimize_fulltext_only = ON ile OPTIMIZE TABLE komutunu çalıştırmanız gerekir.

Bir de sorgulayarak silinmez ancak tasfiye kayıt sayısını inceleyebilir information_schema.innodb_ft_deleted

Bu sorunu gidermek için, InnoDB FULLTEXT dizinleri olan tablolara karşı düzenli olarak OPTİMİZE TABLOSU çalıştırılmalıdır.


Bu mantığı alıyorum, ama doğrulayabilir innodb_optimize_fulltext_only=1ve bir OPTIMIZEtablo aslında "bekleyen" silinmiş satırları ilgilenir? dba.stackexchange.com/questions/174486/…
Riedsio


0

MySQL'deki tam metin dizinleri büyük miktarda veriyi desteklemek için tasarlanmamıştır, bu nedenle veri kümeniz büyüdükçe arama hızı oldukça hızlı bir şekilde düşer. Çözümlerden biri, gelişmiş arama işlevselliği (alaka ayarı ve sıralı arama desteği, yerleşik yönler, snippet'ler, vb.) Genişletilmiş sorgu sözdizimi ve orta hızda çok daha yüksek hıza sahip Solr veya Sphinx gibi harici tam metin arama motorlarını kullanmaktır. -büyük veri kümeleri.

Solr Java platformuna dayanır, bu nedenle Java tabanlı bir uygulama çalıştırırsanız sizin için doğal bir seçim olacaktır, Sfenks C ++ üzerine yazılır ve MySQL ile aynı şekilde bir daemon görevi görür. Harici motoru aramak istediğiniz verilerle beslediğiniz anda, bazı sorguları MySQL dışına da taşıyabilirsiniz. Sizin durumunda hangi motorun daha iyi olduğunu söyleyemem, çoğunlukla Sfenks kullanıyorum ve işte kullanım örneği: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.