ดัชนี PostgreSQL และ BRIN
ทดสอบด้วยตัวคุณเอง นี่ไม่ใช่ปัญหาสำหรับแล็ปท็อปอายุ 5 ปีที่มี ssd
EXPLAIN ANALYZE
CREATE TABLE electrothingy
AS
SELECT
x::int AS id,
(x::int % 20000)::int AS locid, -- fake location ids in the range of 1-20000
now() AS tsin, -- static timestmap
97.5::numeric(5,2) AS temp, -- static temp
x::int AS usage -- usage the same as id not sure what we want here.
FROM generate_series(1,1728000000) -- for 1.7 billion rows
AS gs(x);
QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------
Function Scan on generate_series gs (cost=0.00..15.00 rows=1000 width=4) (actual time=173119.796..750391.668 rows=1728000000 loops=1)
Planning time: 0.099 ms
Execution time: 1343954.446 ms
(3 rows)
ดังนั้นใช้เวลา 22 นาทีในการสร้างตาราง ส่วนใหญ่เนื่องจากตารางเป็น 97GB ที่เรียบง่าย ต่อไปเราจะสร้างดัชนี
CREATE INDEX ON electrothingy USING brin (tsin);
CREATE INDEX ON electrothingy USING brin (id);
VACUUM ANALYZE electrothingy;
ใช้เวลานานพอสมควรในการสร้างดัชนีเช่นกัน แม้ว่าพวกเขาจะเป็น BRIN พวกเขามีเพียง 2-3 MB และพวกเขาเก็บไว้ใน RAM ได้อย่างง่ายดาย การอ่าน 96 GB ไม่ได้เกิดขึ้นทันที แต่ไม่ใช่ปัญหาที่แท้จริงสำหรับแล็ปท็อปของฉันที่ภาระงานของคุณ
ตอนนี้เราค้นหามัน
explain analyze
SELECT max(temp)
FROM electrothingy
WHERE id BETWEEN 1000000 AND 1001000;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=5245.22..5245.23 rows=1 width=7) (actual time=42.317..42.317 rows=1 loops=1)
-> Bitmap Heap Scan on electrothingy (cost=1282.17..5242.73 rows=993 width=7) (actual time=40.619..42.158 rows=1001 loops=1)
Recheck Cond: ((id >= 1000000) AND (id <= 1001000))
Rows Removed by Index Recheck: 16407
Heap Blocks: lossy=128
-> Bitmap Index Scan on electrothingy_id_idx (cost=0.00..1281.93 rows=993 width=0) (actual time=39.769..39.769 rows=1280 loops=1)
Index Cond: ((id >= 1000000) AND (id <= 1001000))
Planning time: 0.238 ms
Execution time: 42.373 ms
(9 rows)
อัปเดตด้วยการประทับเวลา
ที่นี่เราสร้างตารางที่มีการประทับเวลาที่แตกต่างกันเพื่อตอบสนองคำขอการจัดทำดัชนีและค้นหาในคอลัมน์การประทับเวลาการสร้างใช้เวลานานขึ้นเล็กน้อยเนื่องจากto_timestamp(int)
ช้ากว่าnow()
(ซึ่งแคชสำหรับธุรกรรม)
EXPLAIN ANALYZE
CREATE TABLE electrothingy
AS
SELECT
x::int AS id,
(x::int % 20000)::int AS locid,
-- here we use to_timestamp rather than now(), we
-- this calculates seconds since epoch using the gs(x) as the offset
to_timestamp(x::int) AS tsin,
97.5::numeric(5,2) AS temp,
x::int AS usage
FROM generate_series(1,1728000000)
AS gs(x);
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------
Function Scan on generate_series gs (cost=0.00..17.50 rows=1000 width=4) (actual time=176163.107..5891430.759 rows=1728000000 loops=1)
Planning time: 0.607 ms
Execution time: 7147449.908 ms
(3 rows)
ตอนนี้เราสามารถเรียกใช้แบบสอบถามด้วยค่าการประทับเวลาแทน ,,
explain analyze
SELECT count(*), min(temp), max(temp)
FROM electrothingy WHERE tsin BETWEEN '1974-01-01' AND '1974-01-02';
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=296073.83..296073.84 rows=1 width=7) (actual time=83.243..83.243 rows=1 loops=1)
-> Bitmap Heap Scan on electrothingy (cost=2460.86..295490.76 rows=77743 width=7) (actual time=41.466..59.442 rows=86401 loops=1)
Recheck Cond: ((tsin >= '1974-01-01 00:00:00-06'::timestamp with time zone) AND (tsin <= '1974-01-02 00:00:00-06'::timestamp with time zone))
Rows Removed by Index Recheck: 18047
Heap Blocks: lossy=768
-> Bitmap Index Scan on electrothingy_tsin_idx (cost=0.00..2441.43 rows=77743 width=0) (actual time=40.217..40.217 rows=7680 loops=1)
Index Cond: ((tsin >= '1974-01-01 00:00:00-06'::timestamp with time zone) AND (tsin <= '1974-01-02 00:00:00-06'::timestamp with time zone))
Planning time: 0.140 ms
Execution time: 83.321 ms
(9 rows)
ผลลัพธ์:
count | min | max
-------+-------+-------
86401 | 97.50 | 97.50
(1 row)
ดังนั้นใน 83.321 ms เราสามารถรวบรวม 86,401 ระเบียนในตารางที่มี 1.7 พันล้านแถว นั่นควรจะสมเหตุสมผล
สิ้นสุดชั่วโมง
การคำนวณการสิ้นสุดชั่วโมงก็ค่อนข้างง่ายเช่นกันตัดส่วนเวลาที่บันทึกไว้ลงแล้วเพิ่มชั่วโมง
SELECT date_trunc('hour', tsin) + '1 hour' AS tsin,
count(*),
min(temp),
max(temp)
FROM electrothingy
WHERE tsin >= '1974-01-01'
AND tsin < '1974-01-02'
GROUP BY date_trunc('hour', tsin)
ORDER BY 1;
tsin | count | min | max
------------------------+-------+-------+-------
1974-01-01 01:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 02:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 03:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 04:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 05:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 06:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 07:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 08:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 09:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 10:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 11:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 12:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 13:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 14:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 15:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 16:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 17:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 18:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 19:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 20:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 21:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 22:00:00-06 | 3600 | 97.50 | 97.50
1974-01-01 23:00:00-06 | 3600 | 97.50 | 97.50
1974-01-02 00:00:00-06 | 3600 | 97.50 | 97.50
(24 rows)
Time: 116.695 ms
สิ่งสำคัญที่ควรทราบคือไม่ได้ใช้ดัชนีในการรวมตัว แต่อาจทำได้ ถ้านั่นเป็นคำถามของคุณโดยทั่วไปคุณอาจต้องการให้ BRIN อยู่ในdate_trunc('hour', tsin)
นั้นปัญหาเล็ก ๆ ที่date_trunc
ไม่สามารถเปลี่ยนไม่ได้ดังนั้นคุณต้องห่อมันก่อนเพื่อให้มันเป็นเช่นนั้น
การแยก
อีกจุดที่สำคัญของข้อมูลเกี่ยวกับ PostgreSQL เป็นที่ PG 10 นำมาแบ่งพาร์ทิชัน DDL ตัวอย่างเช่นคุณสามารถสร้างพาร์ติชันได้อย่างง่ายดายทุกปี ทำลายฐานข้อมูลขนาดเล็กของคุณให้เล็กลง ในการทำเช่นนี้คุณควรใช้และรักษาดัชนี btree มากกว่า BRIN ซึ่งจะเร็วยิ่งขึ้น
CREATE TABLE electrothingy_y2016 PARTITION OF electrothingy
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01');
หรืออะไรก็ตาม