Так как я молодой разработчик и не очень разбираюсь в использовании баз данных (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
Я работал над приложением, которое считывало миллиарды показаний электрических счетчиков и выполняло большинство запросов менее чем за 10 секунд.
Наша среда была другой. Microsoft SQL Server на компьютере серверного класса (4 ядра, 24 ГБ памяти). Есть ли шанс перейти на сервер?
Одна большая проблема заключается в том, что прием показаний по одному оказал большое влияние на производительность базы данных. Для записи данных требуются блокировки, а запросы будут ждать. Вы можете сделать вставки в партиях?
С вашей схемой у вас будет 4 очень больших таблицы. Важно, чтобы все ваши объединения использовали индексы для обеих таблиц. Сканирование таблицы займет вечность. Возможно ли объединить их в 1 таблицу с пустыми полями?
источник
Вы выходите за пределы встроенной масштабируемости Postgres (или любой другой RDBMS).
Помните, что индекс RDBMS - это B-дерево. B-Tree - это O (log n) как для среднего, так и для наихудшего случая. Это делает его хорошим, безопасным, предсказуемым выбором для разумных значений N. Он ломается, когда N становится слишком большим.
Базы данных NoSQL - это (по большей части) хеш-таблицы. Хеш-таблица - это O (1) в среднем случае и O (n) в худшем случае. Предполагая, что вы можете избежать наихудшего случая, он работает очень хорошо для очень больших значений N.
Кроме того, хеш-таблицу легко распараллелить, а b-дерево - нет. Это делает хеш-таблицы более подходящими для архитектуры распределенных вычислений.
Когда вы начнете получать миллиардные таблицы строк, самое время подумать о переключении с RDBMS на NoSQL. Кассандра, вероятно, будет хорошим выбором для вашего случая использования.
источник