Так как я молодой разработчик и не очень разбираюсь в использовании баз данных (PostgreSQL 9.3), я столкнулся с некоторыми проблемами в проекте, где мне действительно нужна помощь.
Мой проект о сборе данных с устройств (до 1000 или более устройств), где каждое устройство отправляет один блок данных каждую секунду, что составляет около 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);
...
Возможно, что в одном блоке данных есть 3x dataA, 1x dataB, но нет dataC.
Данные будут храниться в течение нескольких недель, поэтому в этой таблице будет около 5 миллиардов строк. На данный момент в таблице ~ 600 миллионов строк, и мои запросы занимают очень много времени. Поэтому я решил создать индекс заново timestamp
и mac
, потому что мои операторы select всегда запрашивают со временем, а часто и со временем + mac.
CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);
... но мои запросы все еще занимают много времени. Например, я запросил данные за один день и один 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
Я сделал полный вакуум перед запуском запроса. Есть ли элегантный способ решить такую проблему с большими таблицами, чтобы сделать запрос <10 секунд?
Я читал о разделении, но это не будет работать с моими 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,10 ГГц, 4 ГБ оперативной памяти. Мои текущие настройки следующие:
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