PostgreSQL对于相同数据类型的索引创建时间不同

时间:2019-01-03 14:23:58

标签: postgresql

我有一个表,该表具有三列A,B,C,均为bytea类型。 表中大约有180,000,000行。 A,B和C都有正好20个字节的数据,C有时包含NULL

使用

为所有列创建索引时
CREATE INDEX index_A ON transactions USING hash (A);
CREATE INDEX index_B ON transactions USING hash (B);
CREATE INDEX index_C ON transactions USING hash (C);

index_A在大约10分钟内创建,而B和C花费了10多个小时,之后我中止了它们。我自己运行每个CREATE INDEX,因此没有并行创建任何索引。数据库中也没有其他查询在运行。 运行时

SELECT * FROM pg_stat_activity;

wait_event_typewait_event均为NULL,state active

为什么第二个索引创建需要这么长时间,我可以做些什么来加快它们的速度?

1 个答案:

答案 0 :(得分:1)

确保表格上的统计信息是最新的。
然后执行以下查询:

SELECT attname, n_distinct, correlation
from pg_stats
where tablename = '<Your table name here>'

基本上,在以下情况下,数据库将有更多工作来创建索引:

  • 不同值的数量越来越多。
  • 相关性(=是物理上字段中顺序存储的值)接近0。

我怀疑您会发现字段A在不同值和/或更高的correlation方面与其他2个字段有所不同。

编辑:基本上,创建表的索引= FULL SCAN,并在进行过程中在索引中创建条目。您在下面共享的统计信息意味着:

  • A列:被检测为唯一
    只要数据库知道1条记录= 1条索引条目,一次扫描就足够了。
  • B和C列:被检测为具有很少的不同值+ abs(correlation)非常低。
    每个索引条目占用表的整个FULL SCAN

注意:简化描述以突出区别。


解决方案1 ​​
不要为B和C创建索引。
听起来可能很愚蠢,但实际上,正如here所述,较小的相关性意味着可能不会使用索引(仅当条目未分散在所有表块中时,索引才有用)。


解决方案2
订购磁盘上的记录。
初始化将是这样的:

CREATE TABLE Transactions_order as SELECT * FROM Transactions;
TRUNCATE TABLE Transactions;
INSERT INTO Transactions SELECT * FROM Transactions_order ORDER BY B,C,A;
DROP TABLE Transactions_order;

接下来是棘手的部分:使用插入/更新/删除记录,您需要跟踪相关性并确保相关性不会下降太多。
如果不能保证,请遵循解决方案1。


解决方案3 : 创建partitions并享受分区修剪的功能。
最近在postgresql中进行了大量的分区工作。值得一看。