ผลลัพธ์อธิบายของ MySQL ค่อนข้างตรงไปตรงมา PostgreSQL มีความซับซ้อนกว่าเล็กน้อย ฉันไม่สามารถหาแหล่งข้อมูลที่ดีที่อธิบายได้เช่นกัน
คุณสามารถอธิบายสิ่งที่อธิบายได้อย่างชัดเจนหรืออย่างน้อยก็ชี้ให้ฉันเห็นทิศทางของทรัพยากรที่ดี
ผลลัพธ์อธิบายของ MySQL ค่อนข้างตรงไปตรงมา PostgreSQL มีความซับซ้อนกว่าเล็กน้อย ฉันไม่สามารถหาแหล่งข้อมูลที่ดีที่อธิบายได้เช่นกัน
คุณสามารถอธิบายสิ่งที่อธิบายได้อย่างชัดเจนหรืออย่างน้อยก็ชี้ให้ฉันเห็นทิศทางของทรัพยากรที่ดี
คำตอบ:
Explaining_EXPLAIN.pdfก็ช่วยได้เช่นกัน
ส่วนที่ฉันมักจะสับสนคือต้นทุนเริ่มต้นเทียบกับต้นทุนทั้งหมด ฉัน Google ทุกครั้งที่ฉันลืมมันซึ่งทำให้ฉันกลับมาที่นี่ซึ่งไม่ได้อธิบายความแตกต่างนั่นคือเหตุผลที่ฉันเขียนคำตอบนี้ นี่คือสิ่งที่ผมได้รวบรวมจากPostgres EXPLAIN
เอกสาร , อธิบายที่ผมเข้าใจ
นี่คือตัวอย่างจากแอปพลิเคชันที่จัดการฟอรัม:
EXPLAIN SELECT * FROM post LIMIT 50;
Limit (cost=0.00..3.39 rows=50 width=422)
-> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
นี่คือคำอธิบายแบบกราฟิกจาก PgAdmin:
(เมื่อคุณใช้ PgAdmin คุณสามารถชี้เมาส์ไปที่ส่วนประกอบเพื่ออ่านรายละเอียดค่าใช้จ่าย)
ค่าใช้จ่ายจะแสดงเป็นอันดับหนึ่งเช่นค่าใช้จ่ายของการLIMIT
เป็นcost=0.00..3.39
และค่าใช้จ่ายของการสแกนตามลำดับคือpost
cost=0.00..15629.12
จำนวนครั้งแรกใน tuple เป็นค่าใช้จ่ายในการเริ่มต้นและจำนวนที่สองคือค่าใช้จ่ายทั้งหมด เนื่องจากฉันใช้EXPLAIN
และไม่ได้EXPLAIN ANALYZE
ค่าใช้จ่ายเหล่านี้เป็นค่าประมาณไม่ใช่มาตรการจริง
ในฐานะที่เป็นภาวะแทรกซ้อนต้นทุนของโหนด "พาเรนต์" แต่ละโหนดจะรวมค่าใช้จ่ายของโหนดลูกด้วย ในการแสดงข้อความต้นไม้จะแสดงด้วยการเยื้องเช่นLIMIT
เป็นโหนดแม่และSeq Scan
เป็นลูกของมัน ในการแสดง PgAdmin ลูกศรจะชี้จากลูกไปยังแม่ - ทิศทางของการไหลของข้อมูล - ซึ่งอาจสวนทางกันได้หากคุณคุ้นเคยกับทฤษฎีกราฟ
เอกสารกล่าวว่าค่าใช้จ่ายรวมทั้งหมดโหนดลูก แต่แจ้งให้ทราบว่าค่าใช้จ่ายรวมของ บริษัท ใหญ่มีขนาดเล็กกว่าค่าใช้จ่ายทั้งหมดของเด็กมัน3.39
15629.12
ไม่รวมต้นทุนทั้งหมดเนื่องจากส่วนประกอบเช่นLIMIT
ไม่จำเป็นต้องประมวลผลอินพุตทั้งหมด ดูEXPLAIN SELECT * FROM tenk1 WHERE unique1 < 100 AND unique2 > 9000 LIMIT 2;
ตัวอย่างในPostgresEXPLAIN
เอกสาร
ในตัวอย่างด้านบนเวลาเริ่มต้นเป็นศูนย์สำหรับทั้งสององค์ประกอบเนื่องจากองค์ประกอบทั้งสองไม่จำเป็นต้องดำเนินการประมวลผลใด ๆ ก่อนที่จะเริ่มเขียนแถว: การสแกนตามลำดับจะอ่านแถวแรกของตารางและส่งออกมา LIMIT
อ่านแถวแรกและจากนั้นก็ปล่อยออกมา
เมื่อใดที่คอมโพเนนต์จะต้องทำการประมวลผลจำนวนมากก่อนจึงจะเริ่มส่งออกแถวใด ๆ ได้ มีหลายสาเหตุที่เป็นไปได้ แต่ลองดูตัวอย่างที่ชัดเจน นี่คือข้อความค้นหาเดียวกันจากก่อนหน้านี้ แต่ตอนนี้มีORDER BY
อนุประโยค:
EXPLAIN SELECT * FROM post ORDER BY body LIMIT 50;
Limit (cost=23283.24..23283.37 rows=50 width=422)
-> Sort (cost=23283.24..23859.27 rows=230412 width=422)
Sort Key: body
-> Seq Scan on post (cost=0.00..15629.12 rows=230412 width=422)
และแบบกราฟิก:
อีกครั้งการสแกนตามลำดับpost
จะไม่มีค่าใช้จ่ายในการเริ่มต้นระบบจะเริ่มส่งออกแถวทันที แต่การจัดเรียงที่มีค่าใช้จ่ายเริ่มต้นที่สำคัญ23283.24
เพราะมันมีการจัดเรียงทั้งตารางก่อนที่มันจะสามารถส่งออกแม้กระทั่งแถวเดียว ต้นทุนรวมของการจัดเรียง23859.27
จะสูงกว่าต้นทุนเริ่มต้นเพียงเล็กน้อยเท่านั้นซึ่งสะท้อนให้เห็นว่าเมื่อจัดเรียงชุดข้อมูลทั้งหมดแล้วข้อมูลที่เรียงลำดับจะถูกส่งออกไปอย่างรวดเร็ว
สังเกตว่าเวลาLIMIT
23283.24
เริ่มต้นของการจัดเรียงจะเท่ากับเวลาเริ่มต้นของการจัดเรียง นี่ไม่ใช่เพราะLIMIT
ตัวเองมีเวลาเริ่มต้นสูง จริงๆแล้วมันไม่มีเวลาเริ่มต้นด้วยตัวเอง แต่EXPLAIN
จะรวมค่าใช้จ่ายลูกทั้งหมดสำหรับผู้ปกครองแต่ละคนดังนั้นLIMIT
เวลาเริ่มต้นจึงรวมเวลาเริ่มต้นรวมของลูกด้วย
การรวบรวมต้นทุนนี้อาจทำให้ยากที่จะเข้าใจต้นทุนการดำเนินการของแต่ละองค์ประกอบ ตัวอย่างเช่นเราLIMIT
มีเวลาเริ่มต้นเป็นศูนย์ แต่ไม่ชัดเจนในตอนแรก ด้วยเหตุนี้คนอื่น ๆ หลายคนจึงเชื่อมโยงกับExplanation.depesz.comซึ่งเป็นเครื่องมือที่สร้างขึ้นโดย Hubert Lubaczewski (aka depesz) ซึ่งช่วยให้เข้าใจEXPLAIN
โดยการหักต้นทุนเด็กออกจากต้นทุนของผู้ปกครอง เขากล่าวถึงความซับซ้อนอื่น ๆ ในบล็อกโพสต์สั้น ๆเกี่ยวกับเครื่องมือของเขา
มันดำเนินการจากส่วนใหญ่เยื้องไปยังเยื้องน้อยที่สุดและฉันเชื่อว่าจากด้านล่างของแผนไปด้านบน (ดังนั้นหากมีการเยื้องสองส่วนส่วนที่อยู่ไกลออกไปจากหน้าจะดำเนินการก่อนจากนั้นเมื่อพบกับการดำเนินการอื่น ๆ กฎที่รวมเข้าด้วยกันจะดำเนินการ)
แนวคิดก็คือในแต่ละขั้นตอนจะมีชุดข้อมูล 1 หรือ 2 ชุดที่มาถึงและได้รับการประมวลผลโดยกฎบางข้อ หากมีเพียงชุดข้อมูลเดียวการดำเนินการนั้นจะทำกับชุดข้อมูลนั้น (ตัวอย่างเช่นสแกนดัชนีเพื่อดูว่าคุณต้องการแถวใดกรองชุดข้อมูลหรือเรียงลำดับ) ถ้าสองชุดข้อมูลทั้งสองชุดเป็นสองสิ่งที่เยื้องออกไปอีกและจะรวมเข้ากับกฎที่คุณเห็น ความหมายของกฎส่วนใหญ่สามารถเดาได้ง่ายพอสมควร (โดยเฉพาะอย่างยิ่งหากคุณเคยอ่านแผนการอธิบายมาก่อน) อย่างไรก็ตามคุณสามารถลองตรวจสอบแต่ละรายการได้โดยดูในเอกสารหรือ (ง่ายกว่า) โดยเพียงแค่โยนวลีลงใน google EXPLAIN
พร้อมกับไม่กี่คำเช่น
เห็นได้ชัดว่านี่ไม่ใช่คำอธิบายที่สมบูรณ์ แต่มีบริบทเพียงพอที่คุณสามารถหาสิ่งที่คุณต้องการได้ ตัวอย่างเช่นพิจารณาแผนนี้จากฐานข้อมูลจริง:
explain analyze
select a.attributeid, a.attributevalue, b.productid
from orderitemattribute a, orderitem b
where a.orderid = b.orderid
and a.attributeid = 'display-album'
and b.productid = 'ModernBook';
------------------------------------------------------------------------------------------------------------------------------------------------------------
Merge Join (cost=125379.14..125775.12 rows=3311 width=29) (actual time=841.478..841.478 rows=0 loops=1)
Merge Cond: (a.orderid = b.orderid)
-> Sort (cost=109737.32..109881.89 rows=57828 width=23) (actual time=736.163..774.475 rows=16815 loops=1)
Sort Key: a.orderid
Sort Method: quicksort Memory: 1695kB
-> Bitmap Heap Scan on orderitemattribute a (cost=1286.88..105163.27 rows=57828 width=23) (actual time=41.536..612.731 rows=16815 loops=1)
Recheck Cond: ((attributeid)::text = 'display-album'::text)
-> Bitmap Index Scan on (cost=0.00..1272.43 rows=57828 width=0) (actual time=25.033..25.033 rows=16815 loops=1)
Index Cond: ((attributeid)::text = 'display-album'::text)
-> Sort (cost=15641.81..15678.73 rows=14769 width=14) (actual time=14.471..16.898 rows=1109 loops=1)
Sort Key: b.orderid
Sort Method: quicksort Memory: 76kB
-> Bitmap Heap Scan on orderitem b (cost=310.96..14619.03 rows=14769 width=14) (actual time=1.865..8.480 rows=1114 loops=1)
Recheck Cond: ((productid)::text = 'ModernBook'::text)
-> Bitmap Index Scan on id_orderitem_productid (cost=0.00..307.27 rows=14769 width=0) (actual time=1.431..1.431 rows=1114 loops=1)
Index Cond: ((productid)::text = 'ModernBook'::text)
Total runtime: 842.134 ms
(17 rows)
ลองอ่านด้วยตัวคุณเองและดูว่าเข้าท่าไหม
สิ่งที่ฉันอ่านคือฐานข้อมูลจะสแกนid_orderitem_productid
ดัชนีก่อนโดยใช้เพื่อค้นหาแถวที่ต้องการจากorderitem
นั้นจัดเรียงชุดข้อมูลนั้นโดยใช้ Quicksort (การจัดเรียงที่ใช้จะเปลี่ยนไปหากข้อมูลไม่พอดีกับ RAM) จากนั้นจึงตั้งค่าไว้ข้างๆ
จากนั้นจะสแกนorditematt_attributeid_idx
เพื่อค้นหาแถวที่ต้องการจากorderitemattribute
นั้นจัดเรียงชุดข้อมูลนั้นโดยใช้ Quicksort
จากนั้นจะใช้ชุดข้อมูลทั้งสองชุดและรวมเข้าด้วยกัน (การรวมการผสานคือการดำเนินการ "การบีบอัด" แบบหนึ่งที่จะนำชุดข้อมูลที่เรียงลำดับสองชุดไปพร้อมกันโดยปล่อยแถวที่รวมเข้าด้วยกันเมื่อตรงกัน)
อย่างที่ฉันบอกคุณทำงานผ่านแผนส่วนในไปยังส่วนนอกจากล่างขึ้นบน
นอกจากนี้ยังมีเครื่องมือช่วยเหลือออนไลน์Depeszซึ่งจะเน้นว่าส่วนที่มีราคาแพงของผลการวิเคราะห์อยู่ที่ใด
ก็มีหนึ่งนี่คือผลลัพธ์เดียวกันซึ่งสำหรับฉันทำให้ชัดเจนขึ้นว่าปัญหาอยู่ที่ไหน
PgAdminจะแสดงแผนอธิบายแบบกราฟิกให้คุณเห็น การสลับไปมาระหว่างทั้งสองจะช่วยให้คุณเข้าใจความหมายของการแสดงข้อความได้อย่างแท้จริง อย่างไรก็ตามหากคุณแค่อยากรู้ว่าต้องทำอะไรคุณอาจสามารถใช้ GUI ได้ตลอดเวลา
เอกสารอย่างเป็นทางการของ PostgreSQLให้คำอธิบายที่น่าสนใจและละเอียดถี่ถ้วนเกี่ยวกับวิธีทำความเข้าใจผลลัพธ์ของคำอธิบาย
หากคุณติดตั้ง pgadmin จะมีปุ่มอธิบายที่ให้เอาต์พุตข้อความวาดไดอะแกรมของสิ่งที่เกิดขึ้นแสดงตัวกรองประเภทและการรวมชุดย่อยที่ฉันคิดว่ามีประโยชน์มากในการดูว่าเกิดอะไรขึ้น