我在一个大表上有一个简单的查询:
UPDATE a
SET a.xyz = b.xyz
FROM b
WHERE a.xyz IS NULL AND b.id=a.id
现在所有的a.xyz都不是NULL。但是查询执行的时间几乎与所有a.xyz为NULL时一样长(5分钟)。
以下内容在不到一秒的时间内执行
UPDATE a
SET a.xyz = 1
WHERE a.xyz IS NULL
所以,我想知道当大多数a.xyz不是NULL时是否有办法加速第一个查询
P.S。澄清:是的,a.xyz,b.xyz,a.id,b.id上的索引存在
P.S.2。在(a.xyz,a.id)上添加复合索引并在a.xyz WHERE a.xyz IS NULL上添加索引后,时间下降到83秒。但是必须有一种方法可以将其降低到不到一秒,因为没有要更新的记录,并且SELECT COUNT(*)FROM WHERE a.xyz IS NULL在不到一秒的时间内执行
P.S.3。解决了。问题在于另一个触发器无意中触发更新。 (a.xyz,a.id)上的复合索引和a.xyz上的附加索引WHERE a.xyz IS NULL似乎解决了剩余的速度问题
答案 0 :(得分:1)
确保您拥有a.id
和b.id
使用EXPLAIN
运行查询以查看数据库引擎使用的计划。如果说Index Scan
你没有索引,你应该寻找Seq Scan
的内容。
EXPLAIN ANALYZE
UPDATE a
SET a.xyz = b.xyz
FROM b
WHERE a.xyz IS NULL AND b.id=a.id
此外,如果您使用(a.id, a.xyz)
创建复合索引,则可以获得更好的性能
以下是一个例子:
EXPLAIN ANALYZE
SELECT *
FROM projects
JOIN images
using (project_id)
WHERE project_id =1
你可以看到project_pk有项目索引,但没有图像索引。
"Nested Loop (cost=0.15..17.31 rows=273 width=92) (actual time=0.029..0.110 rows=320 loops=1)"
" -> Index Scan using project_pk on projects (cost=0.15..8.17 rows=1 width=52) (actual time=0.012..0.013 rows=1 loops=1)"
" Index Cond: (project_id = 1)"
" -> Seq Scan on images (cost=0.00..6.41 rows=273 width=44) (actual time=0.007..0.049 rows=320 loops=1)"
" Filter: (project_id = 1)"
"Planning time: 0.172 ms"
"Execution time: 0.161 ms"
答案 1 :(得分:1)
在a.xyz
上创建部分索引:
create index a_xyz_null on a (xyz)
where xyz is null
https://www.postgresql.org/docs/9.6/static/indexes-partial.html