Chr*_*isJ 3 postgresql performance statistics execution-plan json postgresql-performance
我试图在 Postgres 9.5 中从这个查询中挤出更多的性能。我正在运行超过 400,000 行。
在玩弄它时,我注意到这些CASE语句增加了相当多的查询成本 - 如果我用简单地对一些现有列求和来替换它们,它会将执行时间减半。有没有更有效的方法来计算这些总和?
SELECT sum("tag1"), sum("tag2"), sum("total_tags")
FROM (
SELECT people.data->'recruiter_id' AS recruiter_id,
(CASE WHEN people.data->'tags' ? 'tag1' THEN 1 END) AS "tag1",
(CASE WHEN people.data->'tags' ? 'tag2' THEN 1 END) AS "tag2",
((CASE WHEN people.data->'tags' ? 'tag1' THEN 1 ELSE 0 END) +
(CASE WHEN people.data->'tags' ? 'tag2' THEN 1 ELSE 0 END)) AS total_tags
FROM people WHERE people.data->'tags' ?| ARRAY['tag1','tag2'] ) AS target
GROUP BY recruiter_id
Run Code Online (Sandbox Code Playgroud)
的输出EXPLAIN ANALYSE:
HashAggregate (cost=1076.30..1078.22 rows=550 width=202) (actual time=7043.115..7043.208 rows=449 loops=1)
Group Key: (people.data -> 'recruiter_id'::text)
-> Bitmap Heap Scan on people (cost=12.85..1072.72 rows=550 width=202) (actual time=13.908..2619.878 rows=48492 loops=1)
Recheck Cond: ((data -> 'tags'::text) ?| '{tag1,tag2}'::text[])
Heap Blocks: exact=26114
-> Bitmap Index Scan on index_people_on_data_tags (cost=0.00..12.82 rows=550 width=0) (actual time=9.219..9.219 rows=48493 loops=1)
Index Cond: ((data -> 'tags'::text) ?| '{tag1,tag2}'::text[])
Planning time: 0.139 ms
Execution time: 7043.291 ms
Run Code Online (Sandbox Code Playgroud)
继续运行:
x86_64-pc-linux-gnu 上的 PostgreSQL 9.5.5,由 gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 编译,64 位
内部查询和外部查询由应用程序的不同部分生成。是否可以在不重组的情况下进行优化?
总的来说,这应该更快更简单:
SELECT *, tag1 + tag2 AS total_tags
FROM (
SELECT (data->>'recruiter_id')::int AS recruiter_id -- cheaper to group by int
, count(*) FILTER (WHERE data->'tags' ? 'tag1') AS tag1
, count(*) FILTER (WHERE data->'tags' ? 'tag2') AS tag2
FROM people
WHERE data->'tags' ?| ARRAY['tag1','tag2']
GROUP BY 1
) target;
Run Code Online (Sandbox Code Playgroud)
假设recruiter_id是整数实体,它是由比所述整数值便宜组jsonb对象含有一个整数数值。我还假设,无论如何,您宁愿在结果中获得整数值。
在子查询中只计数一次,然后在外部添加总和的计数SELECT。
使用聚合FILTER子句进行条件计数:
如果您想要更短的语法,这将为您提供相同的结果和性能:
count(data->'tags' ? 'tag1' OR NULL) AS tag1
Run Code Online (Sandbox Code Playgroud)jsonb通常,索引是大表性能的决定性因素。但是,由于您的查询检索400.000的48.493行,即> 12%,该指数是没有帮助这个查询在所有。
为什么会做出糟糕的决定?查询规划有没有统计的数值内一json/jsonb对象,有选择基于通用的选择性估计最好的查询计划。它期望找到rows = 550而查询实际找到的数量是 ( rows=48493) 的90 倍。使用位图索引扫描的查询计划是一个糟糕的决定。顺序扫描会更快(根本不使用索引)。
索引可能仍然有助于不那么频繁的标签(如果你有那些),一个表达式索引data->'tags'应该是最好的。甚至可能是一个jsonb_path_ops索引,结合一个适应的查询。更多的:
然而,由于这个和其他原因,在使用通用标签时,一个普通的 Postgres 数组或一个完全规范化的模式将远远超过你的jsonb对象的性能。
postgresql-performance 列表中的这个讨论正是关于你的问题:
| 归档时间: |
|
| 查看次数: |
1975 次 |
| 最近记录: |