对billions-rows-table的查询变慢//使用的索引


10

由于我是一名年轻的开发人员,并且不太熟练使用数据库(PostgreSQL 9.3),因此我在一个项目中遇到了一些问题,我确实需要帮助。

我的项目是关于从设备(最多1000台或更多设备)收集数据的,其中每台设备每秒发送一个数据块,每小时大约发送300万行。

目前,我有一张大表,用于存储每个设备的传入数据:

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);
...

一个data_block中可能有3x dataA,1x dataB但没有dataC。

数据将保留几周,因此该表中将有约50亿行。目前,表中有约6亿行,而我的查询要花很长时间。因此,我决定在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.10Ghz,4GB RAM。我当前的设置如下:

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

Answers:


1

这可能反映了我的MS SQL偏见,但我尝试通过将表聚类timestamp。如果您经常在特定时间范围内提取数据,这将有所帮助,因为数据将在物理上连续存储。系统可以搜索到起点,扫描到范围的终点,然后完成。如果您要查询一个特定的小时,则只有3,600,000条记录。

如果您的查询(是...?)是针对特定机器的,则Postgres将需要过滤掉这360万条记录中的99.9%。如果该千分之一过滤器比典型的日期范围拟合器更具选择性,则应使用选择性更大的mac字段作为索引的第一部分。可能仍然值得聚类。

如果仍然不这样做,我会用同样的领域你是索引,要么分区timestampmac

您没有提供数据类型。它们适合数据吗?例如,将日期存储为文本将不必要地使您的表膨胀。


2
Postgres没有聚集索引(尽管它可以将一个表聚集在一个索引上-但这需要手动完成,并且不会“停留”)
a_horse_with_no_name 2014年

谢谢你的建议。现在,它的运行速度比以前快,但每个查询的性能却始终低于30秒。我也做了集群,但是就像@a_horse_with_no_name所说的那样:在postgres中,这是一次性的。我认为我的数据类型是正确的。我在问题中添加了他们
manman 2014年

如果没有群集表,我对范围查询的下一个建议是分区。
所有行业的乔恩2015年

-2

我开发的应用程序从电表读取了数十亿个读数,并在不到10秒的时间内执行了大多数查询。

我们的环境不同。服务器类计算机上的Microsoft SQL Server(4核,24 GB内存)。有机会升级到服务器吗?

一个大问题是,一次读取一个读数会对数据库的性能产生重大影响。写入所需的数据锁和查询将等待。您可以批量插入吗?

使用您的模式,您将有4个非常大的表。所有连接都在两个表上都使用索引,这一点很重要。表扫描将永远进行。将它们合并到具有空字段的1个表中是否可行?


批量插入:我可以进行批量插入,但是目前我正在测试数据库上运行,在该数据库中,查询运行时根本没有插入。但谢谢你,我稍后会想到:) 索引:我在每个表上都有索引。在数据表上,id上的索引,在(mac,timestamp)上的data_block表上。当我在每个左联接中搜索dataA时,问题仍然存在,但没有。即使使用索引,它也会搜索数据表。 可为空的字段:不可能,因为data_block可以具有一种以上的一种数据。1xdata_block-> 4xdataA例如
manman 2014年

您的数据库工具是否提供查询分析器?您可能需要根据id在data_block上建立索引。
KC-NH

我会尽力的,但是我不明白为什么这会有所帮助!
manman 2014年

-2

您正在达到Postgres(或任何其他RDBMS)固有的可伸缩性限制。

请记住,RDBMS索引是B树。对于平均情况和最坏情况,B树都是O(log n)。对于合理的N值,这是一个不错的,安全的,可预测的选择。当N太大时,它就会崩溃。

NoSQL数据库(大多数情况下)是哈希表。哈希表在一般情况下为O(1),在最坏情况下为O(n)。假设您可以避免最坏的情况,那么对于非常大的N值,它的性能确实很好。

另外,哈希表很容易并行化,而b树则不容易。这使哈希表更适合于分布式计算体系结构。

当您开始使用十亿行表时,是时候考虑从RDBMS切换到NoSQL了。对于您的用例,Cassandra可能是一个不错的选择。


2
许多RDBMS具有比B树索引(哈希,位图等)更多的选择。一些DBMS正在存储行,而另一些正在存储列。而且,即使对于数十亿行,O(logn)也不错。使用4GB内存计算机时,它们不可能达到任何极限。
ypercubeᵀᴹ
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.