Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用函数索引优化PostgreSQL?_Postgresql - Fatal编程技术网

使用函数索引优化PostgreSQL?

使用函数索引优化PostgreSQL?,postgresql,Postgresql,在进行一些性能调整时,我遇到了Instagram工程团队的以下帖子: 在我们的一些表上,我们需要索引相当长的字符串(例如,64个字符的base64令牌),在这些字符串上创建索引最终会复制大量数据。对于这些,Postgres的功能索引功能非常有用: CREATE INDEX CONCURRENTLY on tokens (substr(token), 0, 8) 虽然将有多行与该前缀匹配,但让Postgre与这些前缀匹配,然后进行向下筛选很快,结果索引的大小是对整个字符串进行索引时大小的1/1

在进行一些性能调整时,我遇到了Instagram工程团队的以下帖子:

在我们的一些表上,我们需要索引相当长的字符串(例如,64个字符的base64令牌),在这些字符串上创建索引最终会复制大量数据。对于这些,Postgres的功能索引功能非常有用:

CREATE INDEX CONCURRENTLY on tokens (substr(token), 0, 8)
虽然将有多行与该前缀匹配,但让Postgre与这些前缀匹配,然后进行向下筛选很快,结果索引的大小是对整个字符串进行索引时大小的1/10

这看起来是个好主意,所以我尝试了一下——我们有很多项都是由校验和键控的

我们的结果不好。我想知道是否还有其他人运气好

首先,这篇博文看起来是错误的:

CREATE INDEX CONCURRENTLY on tokens (substr(token), 0, 8)
那不应该是

CREATE INDEX CONCURRENTLY on tokens (substr(token, 0, 8));
我们的一个字段基于40个字符的散列。所以我试着:

CREATE INDEX __speed_idx_test_8 on foo (substr(bar, 0, 8));
CREATE INDEX __speed_idx_test_20 on foo (substr(bar, 0, 20));
查询计划器不会使用它

所以我试着:

CREATE INDEX __speed_idx_test_8 on foo (substr(bar, 0, 8));
CREATE INDEX __speed_idx_test_20 on foo (substr(bar, 0, 20));
查询计划器仍然不会使用它

然后我试着:

CREATE INDEX __speed_idx_test_40 on foo (substr(bar, 0, 40));
尽管如此,规划者还是不会使用它

如果我们尝试禁用seq扫描会怎么样

set enable_seqscan=false;
没有

让我们回到原始索引

CREATE INDEX __speed_idx_original on foo (bar);
set enable_seqscan = True;
这就行了

然后我想——也许我需要在查询中使用函数来使用函数索引。因此,我尝试更改查询:

旧的:

新的

这起作用了

是否有人知道,如果不添加额外的搜索条件,是否有可能实现此功能?我不想这样做,但看看文件大小和速度的改进。。。哇

如果你想知道“解释-分析”的输出是什么

-- seq scan
Seq Scan on foo  (cost=10000000000.00..10000073130.77 rows=1 width=1921) (actual time=373.785..1563.551 rows=1 loops=1)
  Filter: (hash = 'eae1d1728963f107fa7d8136bcf7c72572896e1d'::bpchar)
  Rows Removed by Filter: 450252
Total runtime: 1563.687 ms


-- index scan
Index Scan using __speed_idx_original on foo  (cost=0.00..16.53 rows=1 width=1920) (actual time=0.060..0.061 rows=1 loops=1)
  Index Cond: (hash = 'eae1d1728963f107fa7d8136bcf7c72572896e1d'::bpchar)
Total runtime: 1.501 m


-- index scan with substring function
 Index Scan using __speed_idx_test_8 on foo  (cost=0.00..16.37 rows=1 width=1913) (actual time=0.134..0.134 rows=0 loops=1)
  Index Cond: (substr((hash)::text, 0, 8) = 'eae1d172'::text)
  Filter: (hash = 'eae1d1728963f107fa7d8136bcf7c72572896e1d'::bpchar)
Total runtime: 0.216 ms

它仅在使用WHERE子句中的函数时有效。函数签名向查询计划器提示,从函数返回的标量值包含在索引中。
这只适用于不可变函数。Volatile函数(在每次调用时不返回相同结果的函数,如rand())不能使用此方法编制索引。

谢谢。这正是我所想/害怕的。没有办法让PostgreSQL自动意识到这是一个前缀索引。(当然有,但这涉及到为PostgreSQL添加一项功能——请随意资助这项工作!)。因此,您需要修改查询以利用表达式索引。