Các chỉ mục PostgreSQL và BRIN
Kiểm tra nó cho chính mình. Đây không phải là vấn đề trên máy tính xách tay 5 tuổi có 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)
Vì vậy, phải mất 22 phút để tạo bảng. Phần lớn, vì bảng có dung lượng khiêm tốn 97GB. Tiếp theo chúng ta tạo các chỉ mục,
CREATE INDEX ON electrothingy USING brin (tsin);
CREATE INDEX ON electrothingy USING brin (id);
VACUUM ANALYZE electrothingy;
Phải mất một thời gian dài để tạo ra các chỉ mục quá. Mặc dù vì họ BRIN chỉ có 2-3 MB và họ lưu trữ dễ dàng trong ram. Đọc 96 GB không phải là tức thời, nhưng đó không phải là vấn đề thực sự đối với máy tính xách tay của tôi với khối lượng công việc của bạn.
Bây giờ chúng tôi truy vấn nó.
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)
Cập nhật với dấu thời gian
Ở đây chúng tôi tạo một bảng có các dấu thời gian khác nhau để bão hòa yêu cầu lập chỉ mục và tìm kiếm trên cột dấu thời gian, việc tạo ra mất nhiều thời gian hơn vì to_timestamp(int)
chậm hơn đáng kể so với now()
(được lưu trong bộ nhớ cache cho giao dịch)
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)
Bây giờ chúng ta có thể chạy truy vấn trên giá trị dấu thời gian thay thế ,,
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)
Kết quả:
count | min | max
-------+-------+-------
86401 | 97.50 | 97.50
(1 row)
Vì vậy, trong 83.321 ms, chúng ta có thể tổng hợp 86.401 bản ghi trong một bảng với 1,7 tỷ hàng. Điều đó nên hợp lý.
Giờ kết thúc
Tính toán kết thúc giờ cũng khá dễ dàng, cắt bớt dấu thời gian xuống và sau đó chỉ cần thêm một giờ.
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
Điều quan trọng cần lưu ý là nó không sử dụng chỉ mục trên tập hợp, mặc dù có thể. Nếu đó là truy vấn thông thường của bạn, bạn có thể muốn có BRIN date_trunc('hour', tsin)
trong đó có một vấn đề nhỏ date_trunc
không phải là bất biến, vì vậy trước tiên bạn phải bọc nó để biến nó thành như vậy.
Phân vùng
Một điểm quan trọng khác của thông tin trên PostgreSQL là PG 10 mang phân vùng DDL . Vì vậy, bạn có thể, ví dụ, dễ dàng tạo phân vùng cho mỗi năm. Chia nhỏ cơ sở dữ liệu khiêm tốn của bạn thành những cơ sở nhỏ. Khi làm như vậy, bạn sẽ có thể sử dụng và duy trì các chỉ số btree thay vì BRIN, điều này thậm chí sẽ nhanh hơn.
CREATE TABLE electrothingy_y2016 PARTITION OF electrothingy
FOR VALUES FROM ('2016-01-01') TO ('2017-01-01');
Hay bất cứ cái gì.