ผลลัพธ์การค้นหาข้อความแบบเต็มในเวลาจำนวนมากใน 'การกำหนดค่าเริ่มต้น FULLTEXT'


12

ขณะนี้ฉันกำลังพยายามเรียกใช้แบบสอบถามบางอย่างเทียบกับการถ่ายโอนข้อมูลของความคิดเห็นของ Stack Overflow นี่คือลักษณะของสคีมา:

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

ฉันเรียกใช้แบบสอบถามนี้กับตารางและมันทำงานช้าอย่างไม่น่าเชื่อ (มี 29 ล้านแถว แต่มีดัชนีข้อความแบบเต็ม):

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

ดังนั้นฉันจึงทำโปรไฟล์ผลลัพธ์คือ:

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

อย่างที่คุณเห็นมันใช้เวลานานในการเริ่มต้น FULLTEXT เป็นเรื่องปกติหรือไม่ ถ้าไม่ฉันจะแก้ไขได้อย่างไร


แนวคิด: สร้างตารางที่ 2 ที่คุณใส่ความคิดเห็น 1.000 ข้อในช่องข้อความเดียว ตอนนี้คุณค้นหาที่แรกในตารางที่สองนี้และคุณจะได้รับตัวอย่างและid_group 2 id_group 23ด้วยการค้นหาของคุณในตารางหลักของคุณและ จำกัด การสืบค้นของคุณให้อยู่ในช่วง id 2.000 ถึง 2.999 และ 23.000 ถึง 23.999 แน่นอนว่าอันดับที่ 2 จะให้ผลลัพธ์มากกว่าที่คุณต้องการเมื่อคุณรวมความคิดเห็นทั้งหมดที่สร้างชุดค่าผสมของคำหลักใหม่ แต่ท้ายที่สุดแล้วควรเพิ่มความรวดเร็วให้กับทุกสิ่ง แน่นอนมันเพิ่มการใช้พื้นที่ดิสก์เป็นสองเท่า ความคิดเห็นใหม่ควรจะCONCAT'edไปที่ตารางกลุ่ม
mgutt

คำตอบ:


5

คนอื่น ๆ พบว่านี่เป็นสถานการณ์ที่ลำบาก

เนื่องจากเอกสาร MySQL นั้นสั้นมากในสถานะกระทู้นี้

การเริ่มต้น FULLTEXT

เซิร์ฟเวอร์กำลังเตรียมการค้นหาข้อความแบบเต็มภาษา

การขอความช่วยเหลือเพียงอย่างเดียวของคุณคือเตรียมข้อมูลให้น้อยลง ได้อย่างไร

คำแนะนำ # 1

ดูคำถามของคุณอีกครั้ง มันคือการเลือกคอลัมน์ทั้งหมด ฉันจะ refactor แบบสอบถามในการเก็บรวบรวมเฉพาะคอลัมน์ ID socommentsจาก จากนั้นเข้าร่วมรหัสที่ได้รับเหล่านั้นกลับไปที่socommentsตาราง

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

สิ่งนี้อาจสร้างแผนการอธิบายที่น่าเกลียด แต่ฉันคิดว่าการทำโปรไฟล์จะเปลี่ยนให้ดีขึ้น แนวคิดพื้นฐานคือ: หากคุณมีการค้นหาแบบ FULLTEXT ที่ก้าวร้าวทำให้มันรวบรวมข้อมูลจำนวนน้อยที่สุดในช่วงนั้นFULLTEXT initializationซึ่งจะช่วยลดเวลา

ฉันได้แนะนำสิ่งนี้หลายครั้งก่อน

คำแนะนำ # 2

โปรดตรวจสอบว่าคุณกำลังตั้งค่าตัวเลือก FULLTEXT ที่ใช้ InnoDB ไม่ใช่ตัวเลือกสำหรับ MyISAM สองทางเลือกที่คุณควรกังวลคือ

  • innodb_ft_cache_size
    • ค่าที่กำหนด 8000000 (7.629M)
    • ค่าสูงสุด 80000000 (76.29M)
  • innodb_ft_total_cache_size
    • ค่ากำหนด 640000000 (610M)
    • ค่าสูงสุด 1600000000 (1525M = 1.49G)

ลองคิดดูสักครู่ ฟิลด์ข้อความคือ VARCHAR (600) สมมติว่าค่าเฉลี่ยคือ 300 ไบต์ คุณมี 29,000,000 ล้านคน นั่นอาจเป็นเพียง 8GB บางทีการเพิ่มinnodb_ft_cache_sizeและinnodb_ft_total_cache_sizeอาจช่วยได้เช่นกัน

ตรวจสอบให้แน่ใจว่าคุณมี RAM เพียงพอสำหรับบัฟเฟอร์ InnoDB FULLTEXT ที่ใหญ่ขึ้น

ให้มันลอง !!!


ลองใช้คำแนะนำทั้งสองอย่างมันทำให้เวลาลดลงประมาณ 10 วินาทีถึง 200 วินาที สิ่งที่แปลกคือบัฟเฟอร์พูลใช้งานเพียง 9% เท่านั้น ...
hichris123

ลองใส่เครื่องหมายบวกภายในส่วนต่อต้านSELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);และดูว่ามันสร้างความแตกต่างหรือไม่
RolandoMySQLDBA

เหตุผลที่ฉันแนะนำให้ใช้เครื่องหมายบวก? Doc ( dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html ) กล่าวว่า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.ในกรณีของคุณfixed the postต้องมีวลีที่แน่นอน
RolandoMySQLDBA

ผลลัพธ์เดียวกัน เร็วขึ้น & ช้าลงเล็กน้อยดังนั้นอาจเป็นเพราะความแตกต่างในนาทีเมื่อมีการดำเนินการ
hichris123

5

หากคุณกำลังใช้ดัชนี InnoDB FULLTEXT แบบสอบถามมักจะอยู่ในสถานะ "เริ่มต้น FULLTEXT" ถ้าคุณกำลังสอบถามกับตารางที่มีแถวที่ถูกลบเป็นจำนวนมาก ในการใช้งาน FULLTEXT ของ InnoDB แถวที่ถูกลบจะไม่ถูกตัดจนกว่าการดำเนินการ OPTIMIZE ที่ตามมาจะถูกเรียกใช้กับตารางที่ได้รับผลกระทบ ดู: https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

ในการลบรายการดัชนีข้อความแบบเต็มสำหรับบันทึกที่ถูกลบคุณต้องเรียกใช้ตาราง OPTIMIZE บนตารางดัชนีที่มี innodb_optimize_fulltext_only = ON เพื่อสร้างดัชนีข้อความแบบเต็ม

หนึ่งอาจตรวจสอบจำนวนของระเบียนที่ถูกลบ แต่ไม่ได้ลบออกโดยการสอบถามinformation_schema.innodb_ft_deleted

ในการแก้ไขปัญหานี้เราควรเรียกใช้ตาราง OPTIMIZE กับตารางที่มีดัชนี InnoDB FULLTEXT เป็นประจำ


ฉันได้รับตรรกะในเรื่องนี้ แต่คุณสามารถตรวจสอบได้innodb_optimize_fulltext_only=1และOPTIMIZEตารางดูแลแถวที่ถูกลบ "รอ" หรือไม่? dba.stackexchange.com/questions/174486/…
Riedsio

1

มีข้อผิดพลาดที่ยืนยันใน MySQL ( DOCID ที่ถูกลบจะไม่ได้รับการปรับปรุงในช่วง OPTIMIZE ของตาราง InnoDB FULLTEXT ) ที่มีประสิทธิภาพการทำงานของรถถังภายใต้โหลดลบหนัก ๆ (โดยไม่ต้องสร้างตารางใหม่ตั้งแต่เริ่มต้น)

ที่เกี่ยวข้อง


0

ดัชนีข้อความแบบเต็มใน MySQL ไม่ได้ออกแบบมาเพื่อรองรับข้อมูลจำนวนมากดังนั้นความเร็วในการค้นหาจึงลดลงอย่างรวดเร็วเมื่อชุดข้อมูลของคุณเติบโตขึ้น หนึ่งในโซลูชันคือการใช้เอ็นจิ้นการค้นหาข้อความแบบเต็มภายนอกเช่น Solr หรือสฟิงซ์ซึ่งได้ปรับปรุงฟังก์ชันการค้นหา (การปรับความเกี่ยวข้องและการสนับสนุนการค้นหาวลี ชุดข้อมูลขนาดใหญ่

Solr ขึ้นอยู่กับแพลตฟอร์ม Java ดังนั้นหากคุณเรียกใช้แอพพลิเคชั่นที่ใช้ Java เป็นตัวเลือกที่เป็นธรรมชาติสำหรับคุณสฟิงซ์เขียนบน C ++ และทำหน้าที่เป็น daemon ในแบบเดียวกับ MySQL ทันทีที่คุณป้อนเอนจินภายนอกด้วยข้อมูลที่คุณต้องการค้นหาคุณสามารถย้ายเคียวรีบางส่วนออกจาก MySQL ฉันไม่สามารถบอกได้ว่าเอ็นจิ้นใดดีกว่าในกรณีของคุณฉันใช้สฟิงซ์เป็นส่วนใหญ่และนี่คือตัวอย่างการใช้งาน: http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.