it-swarm.asia

لماذا تكون السرعة أكبر بأربع مرات من MATCH ... مرة أخرى على فهرس FULLTEXT في MySQL؟

لا أفهم هذا.

لدي جدول بهذه الفهارس

PRIMARY     post_id
INDEX       topic_id
FULLTEXT    post_text

يحتوي الجدول على (فقط) 346000 صف. أحاول تنفيذ استفساريين.

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

يستغرق 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%')

يستغرق 0.027 ثانية.

يوضح EXPLAIN أن الاختلاف الوحيد هو في المفاتيح الممكنة (fulltext يتضمن post_text ، LIKE لا)

هذا غريب حقاً.

ماذا وراء هذا؟ ماذا يحدث في الخلفية؟ كيف يمكن أن يكون LIKE سريعًا جدًا عند عدم استخدام الفهرس و FULLTEXT بطيئًا جدًا عند استخدام الفهرس الخاص به؟

تحديث 1:

في الواقع ، يستغرق الأمر الآن حوالي 0.5 ثانية ، ربما تم تأمين الجدول ، ولكن لا يزال ، عندما أقوم بتشغيل ملف التعريف ، يظهر أن عملية FULLTEXT INITIALIZATION تستغرق 0.2 ثانية. ماذا تفعل؟

يمكنني الاستعلام عن جدولي باستخدام LIKE 10x في الثانية ، مع النص الكامل 2x فقط

تحديث 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)

لذلك أنا أسأل كيف هذا ممكن؟

بالإضافة إلى،

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

بطيء حقا. يمكن أن يكون النص الكامل أي كسر؟

تحديث 3:

بحق الجحيم؟

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

يستغرق 0.27 ثانية

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

تستغرق أكثر من 30 ثانية! ما يحدث الخطأ هنا؟

12
genesis

أعتقد أن المشكلة قد تنبع من وجود مؤشر FULLTEXT نفسه.

في كل مرة يكون هناك استعلام يتضمن فهرس FULLTEXT ، يميل MySQL Query Optimizer إلى إضعاف الاستعلام في مسح جدول كامل. لقد رأيت هذا على مر السنين. كتبت أيضًا منشورًا سابقًا حول هذا السلوك الأكثر تافهًا في فهارس FULLTEXT .

قد تحتاج إلى القيام بأمرين:

  1. إعادة صياغة الاستعلام بحيث لا يلقي فهرس FULLTEXT مُحسِّن استعلام MySQL في حالة من الارتباك
  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') 

ستحتاج إلى إعادة صياغة الاستعلام مثل هذا:

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

إنشاء مؤشر جديد

ستحتاج إلى فهرس لدعم subqueryA. لديك بالفعل فهرس على topic_id. تحتاج إلى استبداله على النحو التالي:

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

جربها !!!

تحديث 2012-03-19 13:08 EDT

جرب هذا أولاً

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

إذا كان هذا يعمل بسرعة وأعاد عددًا صغيرًا من الصفوف ، فجرّب هذا الاستعلام الفرعي المتداخل:

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

تحديث 2012-03-19 13:11 بتوقيت شرق الولايات المتحدة

قارن وقت تشغيل هذا:

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

مع هذا

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

إذا كان وقت التشغيل هو نفسه ، فسيتم تنفيذ بند MATCH في كل صف. كما أشرت سابقًا ، فإن استخدام فهارس FULLTEXT يميل إلى إبطال أي مزايا تمت محاولة المساهمة بها بواسطة MySQL Query Optimizer.

2
RolandoMySQLDBA