Genç bir geliştirici olduğum ve veritabanlarını (PostgreSQL 9.3) kullanma konusunda yetenekli olmadığım için, gerçekten yardıma ihtiyacım olan bir projeyle ilgili bazı sorunlarla karşılaştım.
Projem, her cihazın saniyede bir veri bloğu gönderdiği cihazlardan (1000 veya daha fazla cihaza kadar) veri toplamakla ilgilidir, bu da saatte yaklaşık 3 milyon satır yapar.
Şu anda her cihazın gelen verilerini sakladığım büyük bir tablo var:
CREATE TABLE data_block(
id bigserial
timestamp timestamp
mac bigint
)
Bir veri bloğunun içerebileceği (veya ekleyemediği) çeşitli veri türleri olduğundan data_block
tabloya başvuran başka tablolar da vardır .
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);
...
Bir data_block'ta 3x dataA, 1x dataB olması, ancak dataC olmaması mümkündür.
Veriler birkaç hafta saklanacak, bu yüzden bu tabloda ~ 5 milyar satır olacak. Şu anda, tabloda ~ 600 milyon satır var ve sorgularım çok uzun sürüyor. Bu yüzden bir dizin oluşturmaya karar verdim timestamp
ve mac
çünkü select deyimlerim her zaman zaman içinde ve sıklıkla + mac üzerinde sorgulanıyor.
CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);
... ancak sorgularım hala uzun sürüyor. Örneğin, bir gün ve bir mac için verileri sorguladım:
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
Sorgu çalıştırmadan önce tam bir vakum yaptım. <10sn bir sorgu yapmak için büyük tablolarda böyle bir sorunu çözmek için zarif bir yolu var mı?
Bölümleme hakkında okudum, ama bu benim dataA, dataB, data_block_id için dataC referansları ile çalışmaz değil mi? Bir şekilde çalışırsa, zaman içinde veya mac üzerinde bölümler yapmalı mıyım?
İndeksimi diğer yöne değiştirdim. Önce MAC, sonra zaman damgası, hem de çok fazla performans kazanıyor.
CREATE INDEX index_mac_ts ON data_block (mac, timestamp DESC);
Ancak yine de, sorgular 30 saniyeden fazla sürer. Özellikle LEFT JOIN
veri tablolarımla bir yaptığımda. İşte EXPLAIN ANALYZE
yeni dizine sahip bir sorgu:
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
Maalesef donanımım kesinlikle sınırlı. Intel i3-2100 @ 3.10Ghz, 4GB RAM kullanıyorum. Mevcut ayarlarım aşağıdaki gibidir:
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