ทำไม LIKE ถึงเร็วกว่า MATCH ถึง 4 เท่า ... เทียบกับดัชนี FULLTEXT ใน MySQL


12

ฉันไม่ได้รับสิ่งนี้

ฉันมีตารางที่มีดัชนีเหล่านี้

PRIMARY     post_id
INDEX       topic_id
FULLTEXT    post_text

ตารางมี (เฉพาะ) 346 000 แถว ฉันพยายามที่จะดำเนินการ 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')

ใช้เวลา 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 วินาที

อธิบายว่าแสดงความแตกต่างเพียงอย่างเดียวคือเป็นไปfulltextได้คีย์ (รวม post_text LIKEไม่ได้)

มันแปลกมาก

อะไรอยู่เบื้องหลังสิ่งนี้ เกิดอะไรขึ้นในพื้นหลัง วิธีการอาจLIKEจะเป็นอย่างนั้นอย่างรวดเร็วเมื่อไม่ได้ใช้ดัชนีและ FULLTEXT เพื่อให้ช้าลงเมื่อใช้ดัชนีของตนหรือไม่

UPDATE1:

ที่จริงตอนนี้ใช้เวลาประมาณ 0.5 วินาทีบางทีตารางอาจถูกล็อค แต่ก็ยังเมื่อฉันเปิดการทำโปรไฟล์ก็แสดงให้เห็นว่าการเริ่มต้น FULLTEXT เริ่มต้นใช้เวลา 0.2 วินาที ว่าไง?

ฉันสามารถสืบค้นตารางของฉันด้วยLIKE10x ต่อวินาทีพร้อม fulltext เพียง 2x

UPDATE2:

เซอร์ไพร์ส!

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

ช้ามาก สามารถฟูลเท็กซ์ใดก็ได้ที่เสียหาย?

Update3:

อะไรกันเนี่ย?

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 วินาที! เกิดอะไรขึ้นที่นี่?


เวลาตอบสนองระหว่างทั้งสองสอดคล้องกันมากกว่าการรันหลายครั้งหรือไม่? ฉันอยากจะคิดว่าการแคชดิสก์อาจเข้ามาเล่นซึ่งการทดสอบ "ช้า" ครั้งแรกโหลดข้อมูลทั้งหมดที่ต้องการลงในหน่วยความจำดังนั้นแบบสอบถาม "เร็ว" ที่สองก็รวดเร็วดี
atxdba

ทดสอบการสืบค้นด้วยSQL_NO_CACHEเท่านั้น
mgutt

นี่เป็นคำถาม / คำตอบที่ค่อนข้างเก่า มีความก้าวหน้าจาก mysql / mariadb ตั้งแต่สมัยนั้นไหม
Roman Susi

1
ข้อควรระวัง: ระยะเวลาของคำถาม & คำตอบนี้แสดงว่ามีการพูดถึง MyISAM เท่านั้น การบังคับใช้กับ InnoDB นั้นเป็นปัญหา
Rick James

@RomanSusi - คุณต้องการเริ่มคำถามใหม่สำหรับ InnoDB หรือไม่?
Rick James

คำตอบ:


2

ฉันคิดว่าปัญหาอาจเกิดจากการมีดัชนี FULLTEXT อยู่

ทุกครั้งที่มีการสืบค้นที่เกี่ยวข้องกับดัชนี FULLTEXT เครื่องมือเพิ่มประสิทธิภาพการสืบค้น MySQL มีแนวโน้มที่จะทำให้การสืบค้นเป็นแบบเต็มตาราง ฉันได้เห็นสิ่งนี้ตลอดหลายปีที่ผ่านมา ฉันยังเขียนโพสต์ก่อนหน้านี้เกี่ยวกับเรื่องนี้พฤติกรรมจิ๊บจ๊อยมากที่สุดในดัชนี FULLTEXT

คุณอาจต้องทำสองสิ่ง:

  1. refactor แบบสอบถามเพื่อให้ดัชนี 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') 

คุณจะต้อง refactor แบบสอบถามเช่นนี้:

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 EDT

เปรียบเทียบเวลาทำงานของสิ่งนี้:

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


ดังนั้นคุณอยากบอกว่าคำค้นหาของฉันสแกนทั้งตารางเพราะ topic_id และpost_idสร้างความสับสนใช่ไหม เหตุใดแบบสอบถาม LIKE จึงทำงานได้โดยไม่ต้องมีดัชนีในคอลัมน์เหล่านี้ (topic_id, post_id) ทำไม MYSQL ถึงไม่เลือกอย่างชาญฉลาดtopic_id = 144017 AND post_id != 155352จากนั้นเพียงเบราว์เซอร์ผ่านผลลัพธ์เหล่านี้ และสิ่งที่ถ้า 100k แถวรวมถึงสตริงการค้นหาของฉัน Fulltext ในpost_text? มันจะไม่เลือกพวกเขาทั้งหมดเหรอ?
แหล่งกำเนิด

ที่จริงฉันสับสนมากขึ้น LIKE '% text%' ไม่ใช้ดัชนีอย่างใดอย่างหนึ่งซึ่งหมายความว่าทำการสแกนทั้งตารางดังนั้นทำไมมันจึงเร็ว
แหล่งกำเนิด

โปรดดูUPDATEของฉันฉันคิดว่าคุณจะแก้มันเร็วจริงๆ ฉันจะให้ตัวแทนของคุณถ้าคุณแก้มัน
แหล่งกำเนิด

การตอบกลับการอัพเดตครั้งที่สองของคุณ ข้อความค้นหาที่สองทำงานน้อยกว่า 0.01ms คำถามแรกไม่เสร็จ ทำไมคุณถึงพูดว่า "หากมีเวลาทำงานเหมือนกันส่วนคำสั่ง MATCH จะถูกเรียกใช้งานในทุกแถว" ? มันไม่ตรงข้ามกับที่ควรจะเป็นใช่มั้ย ถ้าคุณดูที่นี่คุณจะเห็นว่าฉันไม่ใช่คนเดียวที่มีปัญหานี้
แหล่งกำเนิด

การตอบกลับการอัพเดตครั้งแรกของคุณ แบบสอบถามแรกรันใน 0.01ms, 0 แถว, รายการที่สองส่งคืน "ไม่พบดัชนี FULLTEXT ที่ตรงกับรายการคอลัมน์" อย่างไรก็ตามข้อความค้นหาของคุณที่มี 2 ข้อความค้นหาย่อยทำงานได้อย่างสมบูรณ์!
แหล่งกำเนิด
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.