ใช้คิวรีช้ากับพันล้านแถวตาราง // ดัชนี


10

เนื่องจากฉันเป็นนักพัฒนาอายุน้อยและไม่ชำนาญในการใช้ฐานข้อมูล (PostgreSQL 9.3) ฉันพบปัญหาบางอย่างเกี่ยวกับโครงการที่ฉันต้องการความช่วยเหลือ

โครงการของฉันเกี่ยวกับการรวบรวมข้อมูลจากอุปกรณ์ (มากถึง 1,000 อุปกรณ์ขึ้นไป) ซึ่งทุกอุปกรณ์กำลังส่งข้อมูลหนึ่งบล็อกทุกวินาทีซึ่งจะสร้างประมาณ 3 ล้านแถวต่อชั่วโมง

ขณะนี้ฉันมีตารางขนาดใหญ่หนึ่งตารางที่ฉันเก็บข้อมูลขาเข้าของทุกอุปกรณ์:

CREATE TABLE data_block(
    id bigserial
    timestamp timestamp
    mac bigint
)

เนื่องจากมีข้อมูลหลายประเภทที่บล็อกข้อมูลสามารถ (หรือไม่สามารถ) รวมจึงมีตารางอื่น ๆ ที่อ้างอิงdata_blockตาราง

CREATE TABLE dataA(
    data_block_id bigserial
    data

    CONSTRAINT fkey FOREIGN KEY (data_block_id) REFERENCES data_block(id);
);
CREATE TABLE dataB(...);
CREATE TABLE dataC(...);
CREATE INDEX index_dataA_block_id ON dataA (data_block_id DESC);
...

เป็นไปได้ว่าใน data_block เดียวมี 3x dataA, 1x dataB แต่ไม่มี dataC

ข้อมูลจะถูกเก็บไว้เป็นเวลาหลายสัปดาห์ดังนั้นฉันจะมีแถวประมาณ 5 พันล้านแถวในตารางนี้ ในขณะนี้ฉันมีตารางประมาณ 600 ล้านแถวและข้อความค้นหาของฉันใช้เวลานานมาก ดังนั้นฉันตัดสินใจที่จะทำดัชนีมากกว่าtimestampและmacเพราะคำสั่งที่เลือกของฉันมักจะค้นหาตลอดเวลาและบ่อยครั้งที่เวลา + mac

CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);

... แต่ข้อความค้นหาของฉันยังคงใช้เวลานาน ตัวอย่างเช่นฉันสอบถามข้อมูลสำหรับหนึ่งวันและหนึ่งวัน:

SELECT * FROM data_block 
WHERE timestamp>'2014-09-15' 
AND timestamp<'2014-09-17' 
AND mac=123456789
Index Scan using index_ts_mac on data_block  (cost=0.57..957307.24 rows=315409 width=32) (actual time=39.849..334534.972 rows=285857 loops=1)
  Index Cond: ((timestamp > '2014-09-14 00:00:00'::timestamp without time zone) AND (timestamp < '2014-09-16 00:00:00'::timestamp without time zone) AND (mac = 123456789))
Total runtime: 334642.078 ms

ฉันทำสุญญากาศเต็มก่อนที่จะเรียกใช้คิวรี มีวิธีหรูหราในการแก้ปัญหาดังกล่าวกับตารางใหญ่ทำแบบสอบถาม <10sec?

ฉันอ่านเกี่ยวกับการแบ่งพาร์ติชัน แต่จะไม่สามารถใช้ได้กับ dataA, dataB, dataC ของฉันที่อ้างอิงถึง data_block_id ใช่มั้ย หากใช้งานได้ฉันควรแบ่งพาร์ติชั่นตามช่วงเวลาหรือบน mac

ฉันเปลี่ยนดัชนีเป็นทิศทางอื่น MAC เครื่องแรกจากนั้นประทับเวลาและเพิ่มประสิทธิภาพได้มาก

CREATE INDEX index_mac_ts ON data_block (mac, timestamp DESC);

แต่ก็ยังมีการสืบค้นใช้เวลา> 30 วินาที โดยเฉพาะอย่างยิ่งเมื่อฉันทำLEFT JOINกับตารางข้อมูลของฉัน นี่คือEXPLAIN ANALYZEแบบสอบถามที่มีดัชนีใหม่:

EXPLAIN ANALYZE SELECT * FROM data_block WHERE mac = 123456789 AND timestamp < '2014-10-05 00:00:00' AND timestamp > '2014-10-04 00:00:00'
Bitmap Heap Scan on data_block  (cost=1514.57..89137.07 rows=58667 width=28) (actual time=2420.842..32353.678 rows=51342 loops=1)
  Recheck Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
  ->  Bitmap Index Scan on index_mac_ts  (cost=0.00..1499.90 rows=58667 width=0) (actual time=2399.291..2399.291 rows=51342 loops=1)
        Index Cond: ((mac = 123456789) AND (timestamp < '2014-10-05 00:00:00'::timestamp without time zone) AND (timestamp > '2014-10-04 00:00:00'::timestamp without time zone))
Total runtime: 32360.620 ms 

น่าเสียดายที่ฮาร์ดแวร์ของฉันถูก จำกัด อย่างเข้มงวด ฉันใช้ Intel i3-2100 @ 3.10Ghz, 4GB RAM การตั้งค่าปัจจุบันของฉันมีดังนี้:

default_statistics_target = 100
maintenance_work_mem = 512MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 4GB
work_mem = 512MB
wal_buffers = 16MB
checkpoint_segments = 32
shared_buffers = 2GB
max_connections = 20
random_page_cost = 2

คำตอบ:


1

นี้อาจสะท้อนให้เห็นถึงอคติของฉัน MS SQL timestampแต่ฉันพยายามจัดกลุ่มตารางโดย หากคุณดึงข้อมูลตามช่วงเวลาที่กำหนดบ่อยครั้งสิ่งนี้จะช่วยได้เนื่องจากข้อมูลจะถูกเก็บไว้อย่างต่อเนื่อง ระบบสามารถค้นหาจุดเริ่มต้นสแกนไปยังจุดสิ้นสุดของช่วงและทำได้ หากคุณกำลังสืบค้นชั่วโมงที่เฉพาะเจาะจงนั่นเป็นเพียง 3,600,000 ระเบียน

หากข้อความค้นหาของคุณ (ซึ่งคือ ... ?) ใช้สำหรับเครื่องเฉพาะ Postgres จะต้องกรองระเบียน 3.6 M 99.9% จากนั้น หากตัวกรองแบบหนึ่งในพันตัวนี้เลือกได้มากกว่าตัวเลือกช่วงวันที่ทั่วไปคุณควรใช้macฟิลด์ตัวเลือกเพิ่มเติมเป็นองค์ประกอบแรกของดัชนีของคุณ มันอาจจะยังคงคุ้มค่าการจัดกลุ่ม

หากยังไม่ได้ทำมันฉันพาร์ทิชันโดยสนามเดียวกันกับที่คุณทำดัชนีทั้งสองหรือtimestampmac

คุณไม่ได้ให้ประเภทข้อมูล เหมาะสมกับข้อมูลหรือไม่ การจัดเก็บวันที่เป็นข้อความจะทำให้โต๊ะของคุณไม่จำเป็น


2
Postgres ไม่มีดัชนีคลัสเตอร์ (แม้ว่าจะสามารถจัดกลุ่มตารางตามดัชนี - แต่ต้องทำด้วยตนเองและจะไม่ "อยู่")
a_horse_with_no_name

ขอบคุณสำหรับคำแนะนำ. ตอนนี้มันทำงานเร็วกว่า แต่ก่อน แต่ยังคงมีประสิทธิภาพต่ำกว่า> 30 วินาทีต่อข้อความค้นหา ฉันยังได้จัดกลุ่ม แต่เป็น @a_horse_with_no_name กล่าวว่า: ใน postgres นี้เป็นภาพเดียว ประเภทข้อมูลของฉันถูกต้องฉันคิดว่า ฉันเพิ่มพวกเขาในคำถาม
manman

หากไม่มีตารางคลัสเตอร์คำแนะนำครั้งต่อไปของฉันสำหรับการสืบค้นช่วงจะเป็นการแบ่งพาร์ติชัน
Jon of All Trades

-2

ฉันทำงานกับแอปพลิเคชันที่อ่านค่ามิเตอร์ไฟฟ้านับพันล้านครั้งและดำเนินการสอบถามส่วนใหญ่ภายใน 10 วินาที

สภาพแวดล้อมของเรานั้นแตกต่างกัน Microsoft SQL Server บนเครื่องคลาสเซิร์ฟเวอร์ (4 คอร์, หน่วยความจำ 24 GB) มีโอกาสที่จะอัพเกรดเป็นเซิร์ฟเวอร์หรือไม่?

ปัญหาใหญ่อย่างหนึ่งคือการอ่านการอ่านทีละครั้งมีผลกระทบอย่างมากต่อฐานข้อมูล การเขียนข้อมูลที่ต้องการล็อคและแบบสอบถามจะรอ คุณสามารถแทรกเป็นแบตได้หรือไม่?

ด้วยสคีมาของคุณคุณจะมี 4 ตารางที่มีขนาดใหญ่มาก การเข้าร่วมทั้งหมดของคุณจะใช้ดัชนีในตารางทั้งสองเป็นสิ่งสำคัญ การสแกนตารางจะใช้เวลาตลอดไป เป็นไปได้หรือไม่ที่จะรวมเข้ากับ 1 ตารางที่มีเขตข้อมูลที่เป็นค่าว่างได้?


ส่วนแทรกในแบทช์:ฉันสามารถแทรกจำนวนมากได้ แต่ขณะนี้ฉันกำลังทำงานกับฐานข้อมูลทดสอบซึ่งไม่มีการแทรกส่วนใดทำเลยในขณะที่คิวรีทำงานอยู่ แต่ขอบคุณที่ฉันจะคิดในภายหลัง :) ดัชนี:ฉันมีดัชนีในทุกตาราง บนตารางข้อมูลดัชนีบน id บนตาราง data_block บน (mac, timestamp) ปัญหาก็คือมีเมื่อฉันค้นหา dataA ต่อซ้ายเข้าร่วม แต่ไม่มี แม้จะมีดัชนีก็ค้นหาตารางข้อมูล เขตข้อมูล nullable:เป็นไปไม่ได้เนื่องจาก data_block สามารถมีข้อมูลมากกว่าหนึ่งประเภท 1xdata_block -> 4xdataA เช่น
manman

เครื่องมือฐานข้อมูลของคุณให้ตัววิเคราะห์แบบสอบถามหรือไม่ คุณอาจต้องการดัชนีใน data_block ตามรหัส
KC-NH

ฉันจะลอง แต่ฉันไม่เข้าใจว่าทำไมสิ่งนี้ถึงช่วยได้!
manman

-2

คุณกำลังกดขีดจำกัดความสามารถในการปรับขนาดได้ของ Postgres (หรือ RDBMS อื่น ๆ )

จำไว้ว่าดัชนี RDBMS เป็น B-Tree B-Tree คือ O (log n) สำหรับทั้งกรณีธรรมดาและแย่ที่สุด สิ่งนี้ทำให้มันเป็นตัวเลือกที่ดีปลอดภัยและคาดเดาได้สำหรับค่า N ที่เหมาะสมมันหยุดพักเมื่อ N มีขนาดใหญ่เกินไป

ฐานข้อมูล NoSQL เป็นตารางแฮช (ส่วนใหญ่) ตารางแฮชคือ O (1) ในกรณีโดยเฉลี่ยและ O (n) ในกรณีที่เลวร้ายที่สุด สมมติว่าคุณสามารถหลีกเลี่ยงกรณีที่เลวร้ายที่สุดมันทำงานได้ดีสำหรับค่า N ที่มาก

นอกจากนี้ตารางแฮชนั้นขนานกันได้ง่ายและ b-tree ไม่ใช่ สิ่งนี้ทำให้ตารางแฮชเหมาะสำหรับสถาปัตยกรรมการคำนวณแบบกระจาย

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


2
RDBMS จำนวนมากมีตัวเลือกมากกว่าดัชนีต้นไม้ B (แฮชบิตแมปและอื่น ๆ ) DBMS บางตัวกำลังจัดเก็บแถวและบางส่วนกำลังจัดเก็บคอลัมน์ และ O (logn) ก็ไม่เลวแม้แต่กับแถวหลายพันล้านแถว และพวกเขาไม่สามารถกดปุ่มขีด จำกัด ใด ๆ เมื่อใช้เครื่องหน่วยความจำ 4GB
ypercubeᵀᴹ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.