通过索引数据优化Postgres查询

时间:2018-12-03 08:52:59

标签: postgresql indexing query-performance

我现有的应用程序正在Heroku上运行,并且我使用Postgres作为数据库。

现在,由于数据量的增加,我的查询越来越慢。这是我的查询

SELECT *
FROM my_table
WHERE my_table.is_deleted = $1
  AND my_table.id NOT IN (SELECT my_table_user_actions.qurb_id AS my_table_user_actions_qurb_id
                          FROM my_table_user_actions
                          WHERE my_table_user_actions.user_id = $2
                            AND my_table_user_actions.is_hidden = $3)
  AND my_table.block_x BETWEEN $4 AND $5
  AND my_table.block_y BETWEEN $6 AND $7
  AND my_table.id NOT IN (SELECT sponsored_qurb_log.qurb_id AS sponsored_qurb_log_qurb_id
                          FROM sponsored_qurb_log
                          WHERE sponsored_qurb_log.qurb_id = my_table.id
                            AND sponsored_qurb_log.hash = $8
                            AND sponsored_qurb_log.user_id = $9)) AS anon_1

此查询几乎需要10秒钟才能在服务器上执行。

现在我愿意在以下列上应用索引

  • is_deleted的类型为boolean
  • block_x的类型为int
  • block_y的类型为int

这是三列。这里is_deleted始终设置为false,因为我一直想获取所有未删除的记录。 block_xblock_y是具有经度和纬度的列。

请让我知道查询的索引是什么。

这就是我在想什么

多列索引:

CREATE INDEX my_table_xandy_block ON my_table(blovk_x, block_y);

is_deleted的部分索引:

CREATE INDEX is_deleted_index ON my_table(is_deleted) WHERE is_deleted IS FALSE;

请检查我的查询,然后让我知道如何优化查询。由于我不愿意更改查询,因为我将部署新版本的代码。

1 个答案:

答案 0 :(得分:1)

通常,您必须检查查询的EXPLAIN (ANALYZE, BUFFERS)输出才能回答这样的问题。

但是对于您而言,这很简单:您将必须将NOT IN子句转换为WHERE NOT EXISTS

一个例子:

WHERE a.x NOT IN (
   SELECT b.y FROM b
)

应该成为

WHERE NOT EXISTS (
   SELECT 1 FROM b
   WHERE a.x = b.y
)

这样PostgreSQL可以使用“ antijoin”来处理查询,这对于较大的表将更快。

要进一步加快查询速度,请查看执行计划并适当添加索引。

如果您确实拒绝重写查询,则最好使用以下索引:

CREATE INDEX ON my_table_user_actions (user_id, is_hidden);

CREATE INDEX ON sponsored_qurb_log (qurb_id, hash, user_id);