หากต้องการรายละเอียดเกี่ยวกับคำตอบของ @ alci:
PostgreSQL ไม่สนใจว่าคุณจะเขียนคำสั่งอะไร
PostgreSQL ไม่สนใจเกี่ยวกับลำดับของรายการในWHERE
ประโยคและเลือกดัชนีและคำสั่งการดำเนินการตามการประมาณการต้นทุนและการเลือกเฉพาะเพียงอย่างเดียว
ลำดับที่เข้าร่วมจะเขียนจะถูกละเว้นนอกจากนี้ยังขึ้นอยู่กับการกำหนดค่าjoin_collapse_limit
; หากมีการรวมมากกว่านั้นระบบจะดำเนินการตามลำดับที่เขียน
แบบสอบถามย่อยสามารถดำเนินการก่อนหรือหลังแบบสอบถามที่มีพวกเขาขึ้นอยู่กับสิ่งที่เร็วที่สุดตราบเท่าที่แบบสอบถามย่อยจะถูกดำเนินการก่อนที่แบบสอบถามด้านนอกต้องการข้อมูลจริง บ่อยครั้งในความเป็นจริงแบบสอบถามย่อยจะถูกดำเนินการแบบตรงกลางหรือแทรกด้วยคิวรีด้านนอก
ไม่มีการรับประกัน PostgreSQL จริง ๆ แล้วจะดำเนินการบางส่วนของแบบสอบถามทั้งหมด สามารถเพิ่มประสิทธิภาพได้อย่างสมบูรณ์ นี่เป็นสิ่งสำคัญหากคุณเรียกใช้ฟังก์ชันที่มีผลข้างเคียง
PostgreSQL จะเปลี่ยนการสืบค้นของคุณ
PostgreSQL จะทำการแปลงข้อความค้นหาอย่างหนักในขณะที่ยังคงรักษาเอฟเฟ็กต์ที่เหมือนกันเพื่อให้มันทำงานได้เร็วขึ้นในขณะที่ไม่เปลี่ยนผลลัพธ์
คำที่อยู่นอกเคียวรีย่อยสามารถถูกส่งลงในเคียวรีย่อยเพื่อให้รันเป็นส่วนหนึ่งของเคียวรีย่อยที่คุณไม่ได้เขียนไว้ในเคียวรีภายนอก
คำศัพท์ในแบบสอบถามย่อยสามารถดึงขึ้นไปยังแบบสอบถามด้านนอกเพื่อให้การดำเนินการของพวกเขาเป็นส่วนหนึ่งของแบบสอบถามด้านนอกไม่ใช่ที่ที่คุณเขียนพวกเขาในแบบสอบถามย่อย
แบบสอบถามย่อยสามารถและมักจะแบนเข้าร่วมในตารางด้านนอก เช่นเดียวกับสิ่งที่ต้องการEXISTS
และNOT EXISTS
ข้อความค้นหา
จำนวนการดูจะถูกปรับเป็นคิวรีที่ใช้มุมมอง
ฟังก์ชั่น SQL มักจะได้รับการแทรกเข้าไปในแบบสอบถามการโทร
... และมีการแปลงอื่น ๆ อีกมากมายที่ทำกับเคียวรีเช่นการแสดงออกก่อนการประเมินค่าคงที่การยกเลิกการเชื่อมโยงของเคียวรีย่อยบางรายการและเทคนิคการวางแผน / การเพิ่มประสิทธิภาพอื่น ๆ
โดยทั่วไป PostgreSQL สามารถแปลงและเขียนข้อความค้นหาของคุณได้อย่างหนาแน่นจนถึงจุดที่แต่ละแบบสอบถามเหล่านี้:
select my_table.*
from my_table
left join other_table on (my_table.id = other_table.my_table_id)
where other_table.id is null;
select *
from my_table
where not exists (
select 1
from other_table
where other_table.my_table_id = my_table.id
);
select *
from my_table
where my_table.id not in (
select my_table_id
from other_table
where my_table_id is not null
);
โดยปกติจะสร้างแผนแบบสอบถามเดียวกันทั้งหมด (สมมติว่าฉันไม่ได้ทำผิดพลาดโง่ ๆ ในข้างต้น)
ไม่ใช่เรื่องแปลกที่จะพยายามปรับให้เหมาะสมกับแบบสอบถามเพียงเพื่อจะพบว่าผู้วางแผนแบบสอบถามได้ค้นพบเทคนิคที่คุณพยายามและนำไปใช้โดยอัตโนมัติดังนั้นรุ่นที่ปรับปรุงด้วยมือจึงไม่ดีไปกว่าต้นฉบับ
ข้อ จำกัด
เครื่องมือวางแผน / เพิ่มประสิทธิภาพอยู่ไกลจาก omnicient และถูก จำกัด ด้วยความต้องการอย่างแน่นอนว่าไม่สามารถเปลี่ยนผลกระทบของแบบสอบถามข้อมูลที่มีอยู่เพื่อการตัดสินใจกฎที่ใช้และเวลา CPU มันสามารถที่จะใช้จ่ายไตร่ตรองการเพิ่มประสิทธิภาพ ตัวอย่างเช่น:
วางแผนการอาศัยอยู่กับสถิติเก็บไว้โดยANALYZE
(มักจะผ่าน autovacuum) หากสิ่งเหล่านี้ล้าสมัยตัวเลือกแผนอาจไม่ดี
สถิติเป็นเพียงตัวอย่างเท่านั้นดังนั้นพวกเขาจึงอาจทำให้เข้าใจผิดเนื่องจากผลการสุ่มตัวอย่างโดยเฉพาะอย่างยิ่งหากมีตัวอย่างน้อยเกินไป ตัวเลือกแผนไม่ถูกต้องอาจส่งผลให้
สถิติไม่ได้ติดตามข้อมูลบางประเภทเกี่ยวกับตารางเช่นความสัมพันธ์ระหว่างคอลัมน์ สิ่งนี้สามารถนำไปสู่การวางแผนในการตัดสินใจที่ไม่ดีเมื่อมันคิดว่าสิ่งต่าง ๆ เป็นอิสระเมื่อพวกเขาไม่
ผู้วางแผนจะอาศัยพารามิเตอร์ราคาที่ต้องการrandom_page_cost
บอกความเร็วของการดำเนินการต่างๆในระบบเฉพาะที่ติดตั้งไว้ คำแนะนำเหล่านี้เป็นเพียง หากพวกเขาผิดอย่างรุนแรงพวกเขาสามารถนำไปสู่การเลือกแผนไม่ดี
แบบสอบถามย่อยใด ๆ ที่มีLIMIT
หรือOFFSET
ไม่สามารถถูกแบนหรืออาจมีการดึง / กด นี้ไม่ได้หมายความว่ามันจะดำเนินการก่อนที่จะทุกส่วนของแบบสอบถามนอกแม้ว่าหรือแม้กระทั่งว่ามันจะดำเนินการในทุก
คำศัพท์ CTE (ส่วนคำในWITH
แบบสอบถาม) จะถูกดำเนินการอย่างครบถ้วนหากพวกเขาดำเนินการเลย พวกเขาไม่สามารถถูกแบนและคำศัพท์ไม่สามารถถูกผลักหรือดึงข้ามอุปสรรค CTE ได้ คำศัพท์ CTE จะถูกดำเนินการเสมอก่อนที่จะค้นหาครั้งสุดท้าย นี่เป็นพฤติกรรมที่ไม่ได้มาตรฐานของ SQLแต่มีการบันทึกไว้ว่า PostgreSQL ทำงานอย่างไร
PostgreSQL มีความสามารถที่ จำกัด ในการปรับให้เหมาะสมกับการสืบค้นในตารางต่างประเทศsecurity_barrier
มุมมองและความสัมพันธ์ชนิดพิเศษอื่น ๆ
PostgreSQL จะไม่อินไลน์ฟังก์ชั่นที่เขียนด้วยอะไรยกเว้น SQL ธรรมดาและจะไม่ทำการดึง / กดระหว่างมันกับเคียวรีด้านนอก
เครื่องมือวางแผน / เพิ่มประสิทธิภาพนั้นโง่มากเกี่ยวกับการเลือกดัชนีนิพจน์และความแตกต่างของชนิดข้อมูลเล็กน้อยระหว่างดัชนีและนิพจน์
มากขึ้นเช่นกัน
คำค้นหาของคุณ
ในกรณีที่มีการสอบถามของคุณ:
select 1
from workdays day
where day.date_day >= '2014-10-01'
and day.date_day <= '2015-09-30'
and day.offer_id in (
select offer.offer_day
from offer
inner join province on offer.id_province = province.id_province
inner join center cr on cr.id_cr = province.id_cr
where upper(offer.code_status) <> 'A'
and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557')
and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
)
ไม่มีอะไรหยุดมันจากการถูกแบนให้เป็นคิวรีที่ง่ายขึ้นด้วยชุดการรวมเพิ่มและมันก็น่าจะเป็นเช่นนั้น
มันอาจจะกลายเป็นสิ่งที่ต้องการ (ยังไม่ทดลอง):
select 1
from workdays day
inner join offer on day.offer_id = offer.offer_day
inner join province on offer.id_province = province.id_province
inner join center cr on cr.id_cr = province.id_cr
where upper(offer.code_status) <> 'A'
and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557')
and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
and day.date_day >= '2014-10-01'
and day.date_day <= '2015-09-30';
PostgreSQL จะปรับลำดับการเข้าร่วมและวิธีการเข้าร่วมให้เหมาะสมโดยพิจารณาจากการเลือกแถวและการประมาณจำนวนแถวและดัชนีที่มี หากสิ่งเหล่านี้สะท้อนความเป็นจริงอย่างสมเหตุสมผลแล้วมันจะทำการเชื่อมต่อและเรียกใช้ส่วนคำสั่งที่เหมาะสมที่สุด - มักผสมเข้าด้วยกันดังนั้นมันจะทำสิ่งนี้เล็กน้อยจากนั้นสักเล็กน้อยจากนั้นกลับมาที่ส่วนแรก ฯลฯ
วิธีดูว่าเครื่องมือเพิ่มประสิทธิภาพทำอะไร
คุณไม่เห็น SQL ที่ PostgreSQL ปรับคิวรีของคุณให้เหมาะสมเพราะจะแปลง SQL ให้เป็นตัวแทนแผนผังคิวรีภายในจากนั้นปรับเปลี่ยนนั้น คุณสามารถดัมพ์แผนเคียวรีและเปรียบเทียบกับเคียวรีอื่น
ไม่มีวิธีที่จะ "ลดระดับ" แผนการสืบค้นหรือแผนผังแผนภายในกลับเป็น SQL
http://explain.depesz.com/มีตัวช่วยแผนคิวรีที่ดี หากคุณยังใหม่ทั้งหมดในการสอบถามแผน ฯลฯ (ซึ่งในกรณีนี้ฉันประหลาดใจที่คุณทำสิ่งนี้ผ่านการโพสต์นี้) PgAdmin มีตัวแสดงแผนแบบสอบถามแบบกราฟิกที่ให้ข้อมูลน้อยกว่า แต่ง่ายกว่า
การอ่านที่เกี่ยวข้อง:
ขยายลง / pullup และความสามารถแฟบดำเนินการปรับปรุงในแต่ละรุ่น PostgreSQL เป็นมักจะถูกต้องเกี่ยวกับการดึงขึ้น / ผลักดันลง / แฟบตัดสินใจ แต่ไม่เสมอไปดังนั้นบางครั้งคุณต้อง (AB) ใช้ CTE หรือOFFSET 0
สับ หากคุณพบกรณีดังกล่าวให้รายงานข้อผิดพลาดของเครื่องมือวางแผนแบบสอบถาม
หากคุณเป็นคนที่กระตือรือร้นจริง ๆ คุณสามารถใช้debug_print_plans
ตัวเลือกเพื่อดูแผนการสืบค้นข้อมูลดิบ แต่ฉันสัญญาว่าคุณไม่ต้องการอ่าน จริงๆ.