วิธีคัดลอกล้านแถวจากตารางหนึ่งไปยังอีกตารางใน Postgresql ได้อย่างมีประสิทธิภาพ


36

ฉันมีตารางฐานข้อมูลสองตาราง หนึ่งมีหลายร้อยล้านบันทึก historyให้เรียกว่าหนึ่ง อีกอันหนึ่งคำนวณจากรายวันและฉันต้องการคัดลอกบันทึกทั้งหมดลงในรายการhistoryหนึ่ง

สิ่งที่ฉันทำคือเรียกใช้:

INSERT INTO history SELECT * FROM daily

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

มีวิธีอื่นที่มีประสิทธิภาพมากกว่าในการคัดลอกข้อมูลจากตารางหนึ่งไปอีกตารางหนึ่งหรือไม่?

คำตอบ:


10

หากคุณวางแผนที่จะเก็บประวัติเป็นเวลานาน (หลายเดือน) ฉันขอแนะนำให้ดูตัวเลือกการแบ่งพาร์ติชัน - อาจเป็นหนึ่งพาร์ติชันสำหรับแต่ละวันหรือทุกสัปดาห์เป็นต้น มันขึ้นอยู่กับรูปแบบการเข้าถึงของตารางประวัติของคุณด้วย (คุณเรียกใช้คิวรีที่เข้าถึงข้อมูลข้ามวันหรือไม่คุณรวมตัวกันเป็นจำนวนมาก ฯลฯ ) ดูมุมมองที่เป็นรูปธรรมสำหรับการจัดเก็บมวลรวม / สรุป http://www.postgresql.org/docs/9.3/static/ddl-partitioning.html http://www.postgresql.org/docs/9.3/static/sql-creatematerializedview.html


ขอบคุณสำหรับคำตอบ. มันดูเหมือนหนทางเดียวที่จะไป ฉันจะต้องแบ่งพาร์ติชันข้อมูลเป็นเดือนและทำให้การทำดัชนีใหม่ (เนื่องจากการฟื้นฟูดัชนีเป็นปัญหาที่นี่) เร็วกว่ามาก
Milovan Zogovic

16

ดัมพ์ตารางในรูปแบบ csv

COPY table TO '/tmp/table.csv' DELIMITER ',';

ใช้คำสั่ง COPY ซึ่งมีประสิทธิภาพมากกว่าสำหรับข้อมูลจำนวนมาก

COPY table FROM '/tmp/table.csv' DELIMITER ',';

ตรวจสอบเอกสารหลังการขายได้ที่http://www.postgresql.org/docs/current/static/sql-copy.htmlสำหรับข้อมูลเพิ่มเติม


1
มันยังทำงานอยู่ช้ามาก ... บางทีมันอาจจะต้องทำอะไรบางอย่างกับการสร้างดัชนีที่ยิ่งใหญ่เช่นนี้อีกครั้ง? มี 160 ล้านแถวในhistoryตารางและเราจะต่อท้ายอีก 3 ล้านแถว
Milovan Zogovic

2
ในคุณกำลังเติมตารางว่างหรือเพิ่มแถวมากกว่าที่มีอยู่แล้วโดยปกติแล้วจะมีประสิทธิภาพมากกว่าในการทำดัชนีที่ไม่ทำคลัสเตอร์และสร้างใหม่เมื่อสร้างการถ่ายโอนเสร็จสมบูรณ์ (เว้นแต่มีการใช้งานตารางในเวลานั้น )
David Spillett

BTW นี่เป็นการปิดเครื่องหนึ่งครั้งหรือเป็นสิ่งที่คุณต้องทำอย่างสม่ำเสมอ? หากเป็นประจำฉันมั่นใจว่าคุณสร้างทริกเกอร์เพื่อให้คุณไม่ต้องผ่านการทดสอบนี้ทุกครั้ง
Fabrizio Mazzoni

@FabrizioMazzoni - มันจะต้องมีการดำเนินการในชีวิตประจำวันในเวลาที่กำหนด (kinda การถ่ายภาพในเวลา)
Milovan Zogovic

@DavidSpillett - แน่นอน! การดร็อปดัชนีทำให้การนำเข้าเร็วมาก (ดูคำตอบของฉันด้านบน) อย่างไรก็ตามการสร้างดัชนีใหม่ใช้เวลาหลายชั่วโมง (เนื่องจากฉันมี 160M แถวในฐานข้อมูล) ..
Milovan Zogovic

13

ปัญหาเกิดขึ้นกับดัชนี historyตารางมี 160M แถวจัดทำดัชนี โดยเรียกใช้อย่างใดอย่างหนึ่งCOPY FROMหรือINSERT INTO .. SELECTมันใช้เวลามากที่จะไม่แทรกแถว แต่เพื่อปรับปรุงดัชนี เมื่อฉันปิดการใช้งานดัชนีมันจะนำเข้าแถว 3M ภายใน 10 วินาที ตอนนี้ฉันต้องการค้นหาวิธีการทำดัชนีตารางใหม่อีกครั้งให้เร็วขึ้น


3
คุณต้องการดัชนีในตารางประวัติหรือไม่?
Sherlock

2
เพิ่มดัชนีโดยใช้คำหลักอย่างต่อเนื่อง
Akvel

10

คุณสามารถใช้เครื่องมือpsqlฉันอาจมีประสิทธิภาพดังต่อไปนี้

psql -h ${DAILY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME} -c "copy daily to stdout " | psql -h ${HISTORY_HOST_IP} -p ${PG_PORT} ${DB_NAME} ${USER_NAME}  -c "copy history from stdin"

นอกจากนี้คุณสามารถเขียนเชลล์สคริปต์


ทางออกที่ดีโดยไม่มีไฟล์ระดับกลาง เร็วมากฉันคัดลอกตาราง 950 ล้านแถวใน 1h20 (ไม่มีดัชนี) ระหว่างดิสก์ปกติและระบบไฟล์เครือข่าย
Le Droid

3

นี่ไม่ใช่คำตอบที่แน่นอนสำหรับคำถามของคุณ แต่ถ้าคุณไม่จำเป็นต้องเข้าถึงhistoryตารางคุณสามารถสร้าง SQL dump ได้เช่นกัน:

pg_dump -h host -p port -w -U user db > dump.sql

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

git add dump.sql
git commit -m "temp dump"
git gc --aggressive

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

คุณสามารถใช้crontabงานที่ประมวลผลดัมพ์ได้ทุกวัน

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