我如何知道查询中是不是使用了任何索引 | PostgreSQL 11?

Posted

技术标签:

【中文标题】我如何知道查询中是不是使用了任何索引 | PostgreSQL 11?【英文标题】:How do I know if any index is used in a query | PostgreSQL 11?我如何知道查询中是否使用了任何索引 | PostgreSQL 11? 【发布时间】:2019-05-08 19:57:23 【问题描述】:

我有点困惑,需要一些建议。我使用PostgreSQL 11 数据库。我有这么简单的sql语句:

SELECT DISTINCT "CITY", "AREA", "REGION"
    FROM youtube
WHERE
    "CITY" IS NOT NULL
AND
    "AREA" IS NOT NULL
AND
    "REGION" IS NOT NULL

我在sql语句中使用的youtube表有2500万条记录。我认为这就是为什么查询需要 15-17 秒才能完成。对于我使用该查询的 Web 项目,它太长了。我正在尝试加快请求速度。

我为 youtube 表创建了这样的索引:

CREATE INDEX youtube_location_idx ON public.youtube USING btree ("CITY", "AREA", "REGION");

在这一步之后,我再次运行查询,但需要同样的时间才能完成。似乎查询不使用索引。我如何知道查询中是否使用了任何索引?

解释分析返回:

【问题讨论】:

它没有使用索引。它正在对表进行全表扫描(Seq Scan)。 好像是这样。那么我怎么能告诉 PostgreSQL 11 数据库使用我创建的特定索引呢? 它可能永远不会使用该索引,而优化器会选择执行全表扫描。 NULL 不会被索引,因此 NOT NULL 不一定由您刚刚构建的索引提供帮助。阅读this prior question/answer 你在表中存储了哪些记录,它的主键是什么?如果 Area、region 等独立于主键,则应考虑为 AREA、REGION 和 CODES 设置单独的表,并仅使用外键将它们的 id 存储在主表中。 【参考方案1】:

我知道 PostgreSQL 中有四种类型的扫描。

顺序扫描:不使用索引。

索引扫描:先搜索索引,然后搜索表。

仅索引扫描:仅搜索索引,不扫描实际表。

位图堆扫描:在索引扫描和顺序扫描之间。

结果的第三行(seq scan)显示它按顺序扫描整个表。所以你没有使用索引。

【讨论】:

【参考方案2】:

您自己通过运行EXPLAIN 回答了标题中的问题。查询计划显示使用了哪些索引以及如何使用。详见手册"Using EXPLAIN"章节。

至于为什么查询使用顺序扫描并且没有索引:2500 万行,2992781 rows removed。您正在获取24709900 rows,这几乎是所有行。

这永远不会很快。 这永远不会使用索引。

使用索引只对所有行的一小部分有意义。否则只会增加额外的成本。根据许多共同因素,Postgres 查询计划器开始考虑为所有行的大约 5% 或更少的 btree 索引。相关:

Postgres not using index when index scan is much better option

好吧,如果您的表格行比SELECT 列表中的三列宽得多,那么如果您从中获得仅索引扫描,那么部分覆盖 索引可能会有所帮助。再次,需要满足一些先决条件。而且每个索引也有存储和维护成本。

旁白:一条评论声称,NULL 值无法被索引。这是不正确的,NULL 值可以被索引。不如其他值有效,但没有太大区别。也与手头的案子无关。

【讨论】:

感谢您提供此信息。就我而言,您如何看待partitioning @NurzhanNogerbek:分区对您没有帮助。快速存储、大量 RAM(用于重复调用)和与服务器的快速连接会有所帮助。 (通过网络传输数据可能是这里的瓶颈。)您需要获取几乎所有的行吗?这是这里的核心问题。 好吧,如果我为列 CITYAREAREGION 设置特定值,那么分区无论如何都会有帮助吗? 分区对这个查询没有帮助。时期。不确定 “为列设置特定值” 应该是什么意思。问题是:您是否需要检索 24M 行以及为什么使用 DISTINCT?让它变得更贵了。 set specific values to columns 我的意思是说我们使用这样的查询:SELECT DISTINCT "CITY", "AREA", "REGION" FROM youtube WHERE "CITY"="Alperton" AND "AREA"="Brent" AND "REGION"="WEMBLEY"。我认为在这种情况下分区可能很有用。听了你的话,我很困惑。我还注意到没有DISTINCT 的查询更快。所以我决定放弃DISTINCT这个命令。【参考方案3】:

我认为您可以对此使用索引。比如:

SELECT "CITY", "AREA", "REGION"
FROM (SELECT DISTINCT ON ("CITY", "AREA", "REGION") "CITY", "AREA", "REGION"
      FROM youtube
      ORDER BY "CITY", "AREA", "REGION"
     ) car
WHERE "CITY" IS NOT NULL AND
      "AREA" IS NOT NULL AND
      "REGION" IS NOT NULL;

这应该为SELECT DISTINCT 使用("CITY", "AREA", "REGION") 上的索引——这对于这个查询来说可能是一个昂贵的操作。

也就是说,查询将返回大量数据。因此,即使使用索引也可能不会显着提高整体性能。

【讨论】:

以上是关于我如何知道查询中是不是使用了任何索引 | PostgreSQL 11?的主要内容,如果未能解决你的问题,请参考以下文章

你可以使用 POST 在 Solr (/select) 中运行查询吗

COUNT(*) 是不是已编入索引?

如何使用索引优化选择查询

使用Lucene 7 OpenNLP查询词性标签

当中间列可以是任何东西时,是不是使用 3 列 SQL 索引?

如何知道拆分字符串的索引是不是存在 C# .NET