ฉันกำลังอัปเดตโดยที่ฉันต้องการความเท่าเทียมกันแน่นอนในtstzrange
ตัวแปร แถว ~ 1M มีการแก้ไขและแบบสอบถามใช้เวลาประมาณ 13 นาที ผลลัพธ์ของEXPLAIN ANALYZE
สามารถเห็นได้ที่นี่และผลลัพธ์ที่แท้จริงแตกต่างอย่างมากจากที่ประเมินโดยผู้วางแผนแบบสอบถาม ปัญหาคือการสแกนดัชนีt_range
คาดว่าจะส่งคืนแถวเดียว
สิ่งนี้น่าจะเกี่ยวข้องกับความจริงที่ว่าสถิติของประเภทช่วงนั้นถูกจัดเก็บแตกต่างจากประเภทอื่น ๆ มองไปที่pg_stats
มุมมองสำหรับคอลัมน์ที่n_distinct
เป็น -1 และสาขาอื่น ๆ (เช่นmost_common_vals
, most_common_freqs
) เป็นที่ว่างเปล่า
อย่างไรก็ตามจะต้องมีสถิติเก็บไว้ในt_range
บางแห่ง การอัปเดตที่คล้ายกันอย่างยิ่งซึ่งฉันใช้ 'ภายใน' บน t_range แทนที่จะใช้ความเท่าเทียมกันที่แน่นอนใช้เวลาประมาณ 4 นาทีในการดำเนินการและใช้แผนคิวรีที่แตกต่างกันอย่างมาก (ดูที่นี่ ) แผนคิวรีที่สองนั้นสมเหตุสมผลสำหรับฉันเพราะทุกแถวในตาราง temp และส่วนสำคัญของตารางประวัติจะถูกนำมาใช้ t_range
ที่สำคัญกว่าการวางแผนแบบสอบถามคาดการณ์ตัวเลขให้ถูกต้องประมาณแถวสำหรับกรอง
การกระจายตัวของt_range
มันค่อนข้างผิดปกติ ฉันใช้ตารางนี้เพื่อเก็บสถานะทางประวัติศาสตร์ของตารางอื่นและการเปลี่ยนแปลงของตารางอื่น ๆ เกิดขึ้นพร้อมกันในการทิ้งขนาดใหญ่ดังนั้นจึงมีค่าที่แตกต่างกันไม่มากt_range
นัก นี่คือการนับที่สอดคล้องกับค่าที่ไม่ซ้ำกันของt_range
:
t_range | count
-------------------------------------------------------------------+---------
["2014-06-12 20:58:21.447478+00","2014-06-27 07:00:00+00") | 994676
["2014-06-12 20:58:21.447478+00","2014-08-01 01:22:14.621887+00") | 36791
["2014-06-27 07:00:00+00","2014-08-01 07:00:01+00") | 1000403
["2014-06-27 07:00:00+00",infinity) | 36791
["2014-08-01 07:00:01+00",infinity) | 999753
การนับสำหรับความแตกต่างt_range
ด้านบนเสร็จสมบูรณ์ดังนั้นความสำคัญของหัวใจคือ ~ 3M (ซึ่ง ~ 1M จะได้รับผลกระทบจากข้อความค้นหาอัปเดตใด ๆ )
เหตุใดแบบสอบถาม 1 จึงทำงานได้แย่กว่าแบบสอบถาม 2 มาก ในกรณีของฉันแบบสอบถาม 2 เป็นตัวทดแทนที่ดี แต่ถ้าต้องการความเท่าเทียมกันของช่วงที่แน่นอนฉันจะให้ Postgres ใช้แผนคิวรีที่ชาญฉลาดได้อย่างไร
คำจำกัดความของตารางที่มีดัชนี (ดร็อปคอลัมน์ที่ไม่เกี่ยวข้อง):
Column | Type | Modifiers
---------------------+-----------+------------------------------------------------------------------------------
history_id | integer | not null default nextval('gtfs_stop_times_history_history_id_seq'::regclass)
t_range | tstzrange | not null
trip_id | text | not null
stop_sequence | integer | not null
shape_dist_traveled | real |
Indexes:
"gtfs_stop_times_history_pkey" PRIMARY KEY, btree (history_id)
"gtfs_stop_times_history_t_range" gist (t_range)
"gtfs_stop_times_history_trip_id" btree (trip_id)
แบบสอบถาม 1:
UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND sth.t_range = '["2014-08-01 07:00:01+00",infinity)'::tstzrange;
แบบสอบถาม 2:
UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND '2014-08-01 07:00:01+00'::timestamptz <@ sth.t_range;
Q1 ปรับปรุง 999753 แถวและปรับปรุง Q2 999753 + 36791 = 1036544 (เช่นตาราง temp เป็นเช่นนั้นทุกแถวที่ตรงกับเงื่อนไขช่วงเวลาจะถูกปรับปรุง)
ฉันลองใช้แบบสอบถามนี้เพื่อตอบสนองต่อความคิดเห็นของ @ ypercube :
แบบสอบถาม 3:
UPDATE gtfs_stop_times_history sth
SET shape_dist_traveled = tt.shape_dist_traveled
FROM gtfs_stop_times_temp tt
WHERE sth.trip_id = tt.trip_id
AND sth.stop_sequence = tt.stop_sequence
AND sth.t_range <@ '["2014-08-01 07:00:01+00",infinity)'::tstzrange
AND '["2014-08-01 07:00:01+00",infinity)'::tstzrange <@ sth.t_range;
แผนแบบสอบถามและผลลัพธ์ (ดูที่นี่ ) อยู่ตรงกลางระหว่างสองกรณีก่อนหน้านี้ (~ 6 นาที)
2016/02/05 แก้ไข
ไม่สามารถเข้าถึงข้อมูลได้อีกต่อไปหลังจาก 1.5 ปีฉันสร้างตารางทดสอบที่มีโครงสร้างเดียวกัน (โดยไม่มีดัชนี) และ cardinality ที่คล้ายกัน คำตอบของ jjanesเสนอว่าสาเหตุอาจเป็นลำดับของตารางชั่วคราวที่ใช้สำหรับการอัพเดต ฉันไม่สามารถทดสอบสมมติฐานได้โดยตรงเพราะฉันไม่สามารถเข้าถึงtrack_io_timing
(ใช้ Amazon RDS)
ผลลัพธ์โดยรวมนั้นเร็วขึ้นมาก (จากหลายปัจจัย) ฉันคาดเดาว่าเป็นเพราะการกำจัดของดัชนีที่สอดคล้องกับคำตอบของเออร์วิน
ในกรณีทดสอบนี้โดยทั่วไปแล้วแบบสอบถาม 1 และ 2 ใช้เวลาเท่ากันเพราะทั้งคู่ใช้การรวมแบบผสาน นั่นคือฉันไม่สามารถเรียกสิ่งที่ก่อให้เกิด Postgres ให้เลือกการเข้าร่วมแฮชดังนั้นฉันจึงไม่มีความชัดเจนว่าทำไม Postgres จึงเลือกการเข้าร่วมแฮชที่มีประสิทธิภาพต่ำในตอนแรก
(lower(t_range),upper(t_range))
เนื่องจากคุณตรวจสอบความเท่าเทียมกัน
(a = b)
สอง "มี" เงื่อนไข(a @> b AND b @> a)
? แผนเปลี่ยนแปลงหรือไม่?