Vì tôi là một nhà phát triển trẻ và không thực sự có kỹ năng sử dụng cơ sở dữ liệu (PostgreQuery 9.3), tôi đã gặp một số vấn đề với một dự án, nơi tôi thực sự cần sự giúp đỡ.
Dự án của tôi là về việc thu thập dữ liệu từ các thiết bị (tối đa 1000 thiết bị trở lên), trong đó mỗi thiết bị đang gửi một khối dữ liệu mỗi giây, tạo ra khoảng 3 triệu hàng mỗi giờ.
Hiện tại tôi có một bảng lớn nơi tôi lưu trữ dữ liệu đến của mọi thiết bị:
CREATE TABLE data_block(
id bigserial
timestamp timestamp
mac bigint
)
Vì có một số loại dữ liệu mà một khối dữ liệu có thể (hoặc không thể) bao gồm, nên có các bảng khác tham chiếu data_block
bảng.
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);
...
Có thể trong một data_block có 3x dataA, 1x dataB, nhưng không có dataC.
Dữ liệu sẽ được lưu giữ trong vài tuần, vì vậy tôi sẽ có ~ 5 tỷ hàng trong bảng này. Hiện tại, tôi có ~ 600 triệu hàng trong bảng và các truy vấn của tôi mất một thời gian rất dài. Vì vậy, tôi quyết định tạo một chỉ mục trên timestamp
và mac
bởi vì các câu lệnh chọn của tôi luôn truy vấn theo thời gian và thường theo thời gian + mac.
CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);
... nhưng các truy vấn của tôi vẫn mất nhiều thời gian. Ví dụ: tôi đã truy vấn dữ liệu trong một ngày và một 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
Tôi đã làm một chân không đầy đủ trước khi chạy truy vấn. Có cách nào hay để giải quyết vấn đề như vậy với các bảng lớn để thực hiện truy vấn <10 giây không?
Tôi đã đọc về phân vùng, nhưng điều này sẽ không hoạt động với các tham chiếu dataA, dataB, dataC của tôi đến data_block_id phải không? Nếu nó hoạt động bằng cách nào đó, tôi nên tạo phân vùng theo thời gian hoặc qua mac?
Tôi đã thay đổi chỉ số của tôi sang hướng khác. MAC đầu tiên, sau đó là dấu thời gian và nó đạt được rất nhiều hiệu suất.
CREATE INDEX index_mac_ts ON data_block (mac, timestamp DESC);
Tuy nhiên, các truy vấn mất> 30 giây. Đặc biệt là khi tôi làm một LEFT JOIN
với các bảng dữ liệu của tôi. Đây là một EXPLAIN ANALYZE
trong những truy vấn với chỉ mục mới:
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
Thật không may phần cứng của tôi bị hạn chế nghiêm ngặt. Tôi đang sử dụng Intel i3-2100 @ 3.10Ghz, RAM 4GB. Cài đặt hiện tại của tôi như sau:
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