首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在PostgreSQL中,哈希子计划是什么意思,最后重写的查询是什么?

在PostgreSQL中,哈希子计划是什么意思,最后重写的查询是什么?
EN

Stack Overflow用户
提问于 2021-05-16 09:43:52
回答 1查看 69关注 0票数 0

这是我几天前发布的一个后续问题。In PostgreSQL what does hashed subplan mean?

下面是我的问题。

我想知道优化器如何重写查询,以及如何在PostgreSQL中读取执行计划。以下是示例代码。

代码语言:javascript
复制
DROP TABLE ords;
CREATE TABLE ords (
ORD_ID INT NOT NULL,
ORD_PROD_ID VARCHAR(2) NOT NULL,
ETC_CONTENT VARCHAR(100));
ALTER TABLE ords ADD CONSTRAINT ords_PK PRIMARY KEY(ORD_ID);
CREATE INDEX ords_X01 ON ords(ORD_PROD_ID);
INSERT INTO ords
SELECT i
      ,chr(64+case when i <= 10 then i else 26 end)
      ,rpad('x',100,'x')
  FROM generate_series(1,10000) a(i);

SELECT COUNT(*) FROM ords WHERE ORD_PROD_ID IN ('A','B','C');

DROP TABLE delivery;
CREATE TABLE delivery (
ORD_ID INT NOT NULL,
VEHICLE_ID VARCHAR(2) NOT NULL,
ETC_REMARKS VARCHAR(100));
ALTER TABLE delivery ADD CONSTRAINT delivery_PK primary key (ORD_ID, VEHICLE_ID);
CREATE INDEX delivery_X01 ON delivery(VEHICLE_ID);
INSERT INTO delivery
SELECT i
     , chr(88 + case when i <= 10 then mod(i,2) else 2 end)
     , rpad('x',100,'x')
  FROM generate_series(1,10000) a(i);

analyze ords;
analyze delivery;
This is the SQL I am interested in.

SELECT *
  FROM ords a
 WHERE ( EXISTS (SELECT 1
                   FROM delivery b
                  WHERE a.ORD_ID = b.ORD_ID
                    AND b.VEHICLE_ID IN ('X','Y')
                 )
         OR a.ORD_PROD_ID IN ('A','B','C')
         );
Here is the execution plan
| Seq Scan on portal.ords a (actual time=0.038..2.027 rows=10 loops=1)                                           |
|   Output: a.ord_id, a.ord_prod_id, a.etc_content                                                               |
|   Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) OR ((a.ord_prod_id)::text = ANY ('{A,B,C}'::text[]))) |
|   Rows Removed by Filter: 9990                                                                                 |
|   Buffers: shared hit=181                                                                                      |
|   SubPlan 1                                                                                                    |
|     ->  Index Only Scan using delivery_pk on portal.delivery b (never executed)                                |
|           Index Cond: (b.ord_id = a.ord_id)                                                                    |
|           Filter: ((b.vehicle_id)::text = ANY ('{X,Y}'::text[]))                                               |
|           Heap Fetches: 0                                                                                      |
|   SubPlan 2                                                                                                    |
|     ->  Index Scan using delivery_x01 on portal.delivery b_1 (actual time=0.023..0.025 rows=10 loops=1)        |
|           Output: b_1.ord_id                                                                                   |
|           Index Cond: ((b_1.vehicle_id)::text = ANY ('{X,Y}'::text[]))                                         |
|           Buffers: shared hit=8                                                                                |
| Planning:                                                                                                      |
|   Buffers: shared hit=78                                                                                       |
| Planning Time: 0.302 ms                                                                                        |
| Execution Time: 2.121 ms 

我不知道优化器是如何转换SQL的。优化器重写的最终SQL是什么?我在上面的SQL中只有一个EXISTS子查询,为什么会有两个子计划?“散列子计划2”是什么意思?如果有人能和我分享一点知识,我将不胜感激。

以下是Laurenz Albe的答案。

您有一种误解,认为优化器会重写SQL语句。事实并非如此。重写查询是查询重写器的工作,例如,它用视图的定义替换视图。优化器提供一系列执行步骤来计算结果。它生成的是计划,而不是SQL语句。优化器计划两种选择:要么为找到的每一行执行子计划1,要么执行子计划2一次(请注意,它独立于a),根据结果构建一个哈希表,并探测在中找到的每一行的哈希。在执行时,PostgreSQL决定使用后一种策略,这就是为什么子计划1永远不会被执行子计划1。

Laurenz的回答启发了我。但是,我想知道查询重写器重写的最终查询是什么。这是我认为查询重写器会做的重写查询。我说的对吗?作为这个问题的读者,你认为最终重写的查询会是什么?

代码语言:javascript
复制
 (
     SELECT *
       FROM ords a
      WHERE EXISTS (SELECT 1
                      FROM delivery b
                     WHERE a.ORD_ID = B.ORD_ID
                       AND b.VEHICLE_ID IN ('X','Y')
                     OFFSET 0 --> the optimizer prevented subquery collapse.
                   )
     *alternative OR*
     SELECT a.*
       FROM ords a *(Semi Hash Join)* delivery b --> the optimizer used b as an build input
      WHERE a.ORD_ID = b.ORD_ID
        AND b.VEHICLE_ID IN ('X','Y') --> the optimzer used the delivery_x01 index.
    )
    *filtered OR*    
    SELECT *
      FROM ords a
     WHERE a.ORD_PROD_ID IN ('A','B','C') --> the optimizer cannot use the ords_x01 index due to the query transformation
EN

回答 1

Stack Overflow用户

发布于 2021-05-16 23:47:09

不是的。子计划不是由重写器生成的,而是由优化器生成的。一旦优化器接管,您就永远离开了SQL的领域。它生成的过程执行步骤不能用声明性SQL语言表示。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67552549

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档