การใช้ LIMIT ปรับปรุงประสิทธิภาพและเห็นได้ชัดเจนหรือไม่


11

ฉันต้องการที่จะเข้าใจต่อไปนี้
สมมติว่าฉันมีแบบสอบถามที่ซับซ้อนด้วยสมมติว่าเข้าร่วม 5 กลุ่มตารางโดยสรุปและสั่งซื้อโดย
ปล่อยให้การปรับให้เหมาะสมกับแบบสอบถามตัวเองเช่นดัชนี ฯลฯ
มีประสิทธิภาพการทำงานที่สำคัญใช้LIMIT? ฉันคิดว่าแบบสอบถามทั้งหมด (และผลลัพธ์) ต้องได้รับการประมวลผลก่อนที่จะใช้ LIMIT ดังนั้นการใช้ LIMIT เพื่อดึงชุดย่อยของผลลัพธ์นี้มีการปรับปรุงที่สำคัญ / ที่สังเกตเห็นได้หรือไม่?


2
ฉันขอแนะนำให้คุณอ่านนี้สำหรับกรณีที่LIMITปรับปรุงประสิทธิภาพ: การเพิ่มประสิทธิภาพการสืบค้น LIMIT
ypercubeᵀᴹ

คำตอบ:


10

หากคุณต้องการใช้ประโยชน์จากLIMITการปรับปรุงประสิทธิภาพคุณต้องมี

  • เข้าใจข้อมูลที่คุณกำลังดึง
  • จัดทำดัชนีที่เหมาะสมตามลำดับที่ถูกต้องของคอลัมน์
  • รับผิดชอบในการปรับโครงสร้างแบบสอบถามอีกครั้ง
  • ใช้LIMITก่อนJOIN

หลักการเหล่านี้สามารถไปได้ไกลหากคุณสามารถดัดแปลงมันได้

ฉันเรียนรู้แนวคิดเหล่านี้โดยดูวิดีโอ YouTube นี้ (ฟังอย่างระมัดระวังผ่านสำเนียงฝรั่งเศส)

ผมใช้แนวคิดเหล่านี้จะตอบคำถามที่ StackOverflow ยากมากเกี่ยวกับการรับด้านบน 40 บทความจากบางตาราง: 12 พฤษภาคม 2011: การดึงข้อมูลแถวเดียวจากตารางที่เข้าร่วม

ในคำตอบของฉันสำหรับคำถามนั้น (16 พฤษภาคม 2011)ฉันเขียนแบบสอบถามต่อไปนี้และทดสอบอย่างละเอียด:

SELECT
  AAA.author_id,
  AAA.date_created,
  IFNULL(BBB.title,'<NO_TITLE>') title,
  IFNULL(CCC.filename,'<NO-IMAGE>') filename,
  IFNULL(CCC.date_added,'<NO-IMAGE-DATE>') image_date
FROM
(
  SELECT
    AA.id,
    AA.date_added,
    BB.author_id,
    BB.date_created
  FROM
  (
    SELECT
      A.id,IFNULL(MAX(B.date_added),'1900-01-01 00:00:00') date_added
      FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A
      LEFT JOIN article_images B ON A.id = B.article_id
      GROUP BY A.id
  ) AA
  INNER JOIN articles BB USING (id)
) AAA
LEFT JOIN article_contents BBB ON AAA.id=BBB.article_id
LEFT JOIN article_images CCC
ON (AAA.id=CCC.article_id AND AAA.date_added=CCC.date_added)
ORDER BY AAA.date_created DESC;

โปรดสังเกตบรรทัดในข้อความค้นหาด้วย LIMIT

      FROM (SELECT id FROM articles ORDER BY date_created DESC LIMIT 40) A

แบบสอบถามย่อยนี้ถูกฝังลึกสามระดับ นี้ได้รับอนุญาตให้ฉันได้รับในช่วง 40 LIMITบทความโดยใช้ จากนั้นฉันก็ทำการเข้าร่วมที่จำเป็นหลังจากนั้น

บทเรียนที่ได้เรียนรู้

  • ทำLIMITภายใน subqueries อาจไม่เคยได้คำตอบเพราะ cardinality LIMITของดัชนีเนื้อหาข้อมูลและขนาดผลชุดจาก หากคุณมี "เป็ดในแถว" ของคุณทั้งหมด (มีสี่หลักการในใจสำหรับการค้นหาของคุณ) คุณจะได้รับผลลัพธ์ที่ดีอย่างน่าประหลาดใจ
  • ทำให้คำค้นหาของคุณง่ายที่สุดเท่าที่จะทำได้LIMITโดยการรวบรวมกุญแจเท่านั้น

ดังนั้น(A [LEFT] JOIN B) LIMIT 100จะเทียบเท่า(A LIMIT 100) [LEFT] JOIN (B LIMIT 100)หรือไม่ การ[LEFT] JOINเข้าร่วมภายนอกหรือภายในหมายถึงอะไร
Jim

มันเป็นเช่น(A LIMIT 100) [LEFT] JOIN Bนั้นมากขึ้น แนวคิดคือการใช้LIMITเพื่อกำหนดขนาดของชุดผลลัพธ์ให้เร็วที่สุด ฉันยังใช้LEFT JOINแทนINNER JOINเพราะLEFT JOINจะรักษาลำดับของปุ่มทางด้านซ้าย
RolandoMySQLDBA

@ จิมไม่พวกเขาไม่ใช่ บางครั้งพวกเขาก็เป็นเช่นนี้(A LEFT JOIN B) GROUP BY A.pk LIMIT 100มักจะสามารถเขียนใหม่เป็น(A LIMIT 100) LEFT JOIN B GROUP BY A.pk(ไม่มีเข้าร่วมที่นี่กับการรวมภายในพวกเขาจะไม่เทียบเท่า.) ตัวอย่างของ Rolando เป็นกรณีดังกล่าว
ypercubeᵀᴹ

@ypercube: ดังนั้นด้วยการรวมภายในไม่ได้ทำอะไรเพื่อรับประโยชน์จาก LIMIT
จิม

ฉันอ้างถึงกลยุทธ์การเขียนใหม่ที่ระบุโดย Rolando แบบสอบถามที่มี JOIN และ LIMIT อาจได้รับประโยชน์เช่นกัน หรือไม่. มันขึ้นอยู่กับ.
ypercubeᵀᴹ

2

เมื่อมีการดำเนินการแบบสอบถามจะได้รับการแปลเป็นแผนซึ่งประกอบด้วยผู้ประกอบการหลายราย ตัวดำเนินการพื้นฐานมีสองประเภท: การบล็อกและการไม่บล็อก ผู้ประกอบการที่ไม่ปิดกั้นดึงแถว (หรือไม่กี่แถว) จากลูกหรือลูกของมันสำหรับแต่ละแถวที่ร้องขอจากมัน ตัวดำเนินการบล็อกในอีกด้านหนึ่งจะต้องอ่านและประมวลผลชุดแถวทั้งหมดของชายด์ทั้งหมดก่อนจึงจะสามารถสร้างเอาต์พุตใด ๆ ได้

Sort เป็นผู้ดำเนินการบล็อกทั่วไป ดังนั้นการเลือกตามคำสั่งโดยไม่ได้รับประโยชน์มากนักจากการ จำกัด อย่างไรก็ตามมี RDBMS ที่สามารถใช้อัลกอริทึมการเรียงลำดับที่ต้องการหน่วยความจำน้อยลงและเร็วขึ้นเมื่อมีการระบุข้อ จำกัด ในกรณีนี้เพียงพอที่จะจัดเก็บแถว n แถวแรกและย้ายออกจากหน่วยความจำเมื่อแถวก่อนหน้าเข้ามา ที่สามารถเพิ่มประสิทธิภาพที่สำคัญ อย่างไรก็ตามฉันไม่แน่ใจ 100% ว่า MySQL มีความสามารถนั้น

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


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

ขึ้นอยู่กับแบบสอบถามและดัชนีที่มีอยู่GROUP BYอาจนำไปสู่แผนการที่ไม่มีการบล็อกตัวดำเนินการ
เซบาสเตียนมีน

0

ในกรณีของฉันฉันสามารถพูดว่าใช่แม้ว่าฉัน (ยัง) ไม่เข้าใจว่าทำไม

SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
  ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511
  AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id;

(result set)

8 rows in set (**18.14 sec**)

บันทึกเวลา: 18 วินาที คำขอเดียวกันที่มีขีด จำกัด ขนาดใหญ่:

SELECT g0_.id AS id_0, COUNT(a1_.id_tarifs) AS sclr_1 
FROM groupe_jardinerie g0_
INNER JOIN articles_tarifs a1_
  ON (a1_.groupe_jardinerie_id = g0_.id)
WHERE g0_.centrale_id = 511 
  AND a1_.date_fin_tarif >= '2018-01-29 10:46:35'
GROUP BY g0_.id
LIMIT 100000000000;

(exact same result set)

8 rows in set (**1.32 sec**)

เร็วกว่าสิบเท่า !!!

อธิบายให้ผลเหมือนกันสำหรับคำขอทั้งสอง

+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
| id | select_type | table | partitions | type   | possible_keys                                     | key     | key_len | ref                          | rows   | filtered | Extra                                        |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+
|  1 | SIMPLE      | a1_   | NULL       | ALL    | IDX_438010BBC10784EF                              | NULL    | NULL    | NULL                         | 795135 |    33.33 | Using where; Using temporary; Using filesort |
|  1 | SIMPLE      | g0_   | NULL       | eq_ref | PRIMARY,IDX_9CA5CF6758A1D71F,IDX_9CA5CF67670C757F | PRIMARY | 4       | phs.a1_.groupe_jardinerie_id |      1 |    50.00 | Using where                                  |
+----+-------------+-------+------------+--------+---------------------------------------------------+---------+---------+------------------------------+--------+----------+----------------------------------------------+

LIMIT ควรแทรกแซงเพียงเพื่อ จำกัด ชุดผลลัพธ์ (เช่นถ้าฉันทำ LIMIT 4 ฉันได้รับเพียง 4 แถวแรกของชุดผลลัพธ์ด้านบน)


คุณใช้เวอร์ชั่นไหนและคุณสามารถสร้างกรณีทดสอบที่เรียบง่ายได้หรือไม่?
Evan Carroll

1
คำตอบของคุณไม่ได้พิสูจน์ผลประโยชน์ใหม่ ๆ LIMITสำหรับ ข้อความค้นหาแรกของคุณทำงานใน 18 วินาทีโดยให้ชุดผลลัพธ์ ข้อมูลทั้งหมดในแบบสอบถามที่ 2 ถูกแคชไว้แล้วในพูลบัฟเฟอร์ InnoDB เนื่องจากแบบสอบถามแรกดังนั้นแน่นอนว่าแบบสอบถามที่ 2 จะต้องเร็วขึ้นแม้ว่าคุณจะเริ่ม mysql ใหม่ให้เรียกใช้แบบสอบถามอันดับที่ 1 เริ่ม mysql ใหม่และเรียกใช้อันดับที่ 2 ข้อความค้นหาคุณจะได้รับผลลัพธ์เดียวกัน . มีผลที่ดีกว่าสำหรับLIMITสามารถมาจากการทำ: 1) LIMITก่อนJOIN2) LIMIT ในการเรียงลำดับหรือASC DESC
RolandoMySQLDBA

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