OTA*_*TAR 2 postgresql indexing performance operator-overloading postgresql-9.5
create table test(
id serial primary key,
tagged smallint[]
);
Run Code Online (Sandbox Code Playgroud)
tagged列上有 gin 索引,带有_int2_ops操作符类:
CREATE INDEX ix ON test USING GIN(col _int2_ops);
当我运行此查询时:
select * from test
where tagged @> ARRAY[11]
order by id limit 100;
Run Code Online (Sandbox Code Playgroud)
EXPLAIN ANALYZE 显示:
限制(cost=0.43..19524.39 rows=100 width=36)(实际时间=25024.124..25027.263 rows=100 loops=1)
-> 使用 test_pkey 进行索引扫描(cost=0.43..508404.37 rows=2604 width=36)(实际时间=25024.121..25027.251 rows=100 loops=1)
过滤器:((标记)::integer[] @> '{11}'::integer[])
过滤器删除的行数:2399999
规划时间:6.912 毫秒
执行时间:25027.307 毫秒
大胆强调我的。为什么将tagged列转换为integer[]类型?我认为这就是为什么不使用 GIN 索引并且查询运行缓慢的原因。
我试过了,WHERE tagged @> ARRAY[11]::smallint[]但得到了这个错误:
Run Code Online (Sandbox Code Playgroud)operator is not unique: smallint[] @> smallint[]
如果我做同样的事情但使用tagged int[]和创建索引
CREATE INDEX ix ON test USING GIN(tagged gin__int_ops);
Run Code Online (Sandbox Code Playgroud)
那么上面的查询使用 GIN 索引:
Run Code Online (Sandbox Code Playgroud)"-> Bitmap Index Scan on ix (cost=0.00..1575.53 rows=2604 width=0) (actual time=382.840..382.840 rows=2604480 loops=1)" " Index Cond: (tagged @> '{11}'::integer[])"
这比以前快一点,但平均需要 10 秒 - 仍然太慢。我想尝试smallint[]而不是int[],也许那会更快......
最有可能的解决方案是对操作符进行模式限定:
SELECT *
FROM test
WHERE tagged OPERATOR(pg_catalog.@>) '{11}'::int2[]
ORDER BY id
LIMIT 100;Run Code Online (Sandbox Code Playgroud)
这是运算符解析的问题(结合类型解析和强制转换上下文)。
在标准 Postgres 中,只有一个候选 operator anyarray @> anyarray,这就是您想要的。
如果您没有安装额外的模块intarray(我的假设),您的设置就可以正常工作,它为integer[] @> integer[].
因此,另一种解决方案是integer[]改用并具有gin__int_ops操作符类的 GIN 索引。或者尝试(intarray 的默认值)gist__int_ops索引。两者都可能更快,但都不允许 NULL 值。
或者您可以重命名intarray运算符@>以消除歧义。(我不会那样做。随之而来的是升级和便携性问题。)
对于涉及至少一个 type 操作数的表达式integer[],Postgres 知道选择哪个操作符:intarray 操作符。但是该索引不适用,因为 intarray 运算符只对integer( int4) not 进行操作int2。并且索引严格绑定到运算符:
但是对于int2[] @> int2[],Postgres 无法确定最佳运算符。两者似乎同样适用。由于pg_catalog模式中提供了默认运算符,而模式中提供了 intarray 运算符public(默认情况下 - 或安装扩展的任何地方),您可以通过使用OPERATOR()构造对运算符进行模式限定来帮助解决难题。有关的:
您收到的错误消息有点误导。但是,如果您仔细观察,会HINT添加一行提示(tada!)指向正确的方向:
Run Code Online (Sandbox Code Playgroud)ERROR: operator is not unique: smallint[] @> smallint[] LINE 1: SELECT NULL::int2[] @> NULL::int2[] ^ HINT: Could not choose a best candidate operator. You might need to add explicit type casts.
您可以调查现有的运营商候选人@>:
SELECT o.oid, *, oprleft::regtype, oprright::regtype, n.nspname
FROM pg_operator o
JOIN pg_namespace n ON n.oid = o.oprnamespace
WHERE oprname = '@>';
Run Code Online (Sandbox Code Playgroud)
另一种替代解决方案是临时(!)设置不同的 search_path,因此只能找到所需的运算符。在同一个交易中:
SET LOCAL search_path = pg_catalog;
SELECT ...
Run Code Online (Sandbox Code Playgroud)
但是,您必须对查询中的所有表进行模式限定。
关于演员背景:
您可以更改castcontextof int2-> int4。但我强烈建议不要这样做。太多可能的副作用:
| 归档时间: |
|
| 查看次数: |
963 次 |
| 最近记录: |