Postgresql

條件子查詢

  • January 9, 2017

我有以下查詢:

SELECT id,
  email,
  first_name as "firstName",
  last_name as "lastName",
  is_active as "isActive",
  password,
  access,
  CASE
    WHEN access < 3 THEN (
      SELECT
        CASE WHEN count(*) = 1 THEN true ELSE false END
      FROM user_rating_entity ure
      WHERE ure.user_id = u.id
        AND ure.rating_entity_id = :re_id
    )
    ELSE true
  END as "isResponsible"
FROM users u
WHERE u.id = :id

如果access > 3是,則欄位“isResponsible”應直接設置為true,不執行子查詢。>=我對訪問和<訪問3的兩種情況都使用了解釋分析,但我得到了相同的輸出。

為什麼呢?

在這裡閱讀查詢計劃有三個重要部分,

  • 跑了嗎。如果是這樣的話,
  • 多少次?
  • 是否相關?

樣本數據

您沒有提供任何範例數據,所以讓我們創建一些。

CREATE TABLE foo AS
SELECT x FROM generate_series(1,100) AS x;

而且,現在讓我們在可能的執行範圍之外執行一個帶有子查詢的基本查詢。

EXPLAIN ANALYZE
SELECT
 x,
 (CASE WHEN x>200 THEN (SELECT sum(x) FROM foo) END)
FROM foo;

該計劃將顯示該案件是伴隨的,但從未執行。

Seq Scan on foo  (cost=2.26..4.51 rows=100 width=4) (actual time=0.017..0.047 rows=100 loops=1)
  InitPlan 1 (returns $0)
    ->  Aggregate  (cost=2.25..2.26 rows=1 width=4) (never executed)
          ->  Seq Scan on foo foo_1  (cost=0.00..2.00 rows=100 width=4) (never executed)
Planning time: 0.101 ms
Execution time: 0.118 ms
(6 rows)

你可以看到**(從不執行)**就Aggregate行了。但是,如果我們將其設置為類似的內容,CASE WHEN x>20 THEN (SELECT sum(x) FROM foo您會看到更多

Seq Scan on foo  (cost=2.26..4.51 rows=100 width=4) (actual time=0.020..0.095 rows=100 loops=1)
  InitPlan 1 (returns $0)
    ->  Aggregate  (cost=2.25..2.26 rows=1 width=4) (actual time=0.043..0.043 rows=1 loops=1)
          ->  Seq Scan on foo foo_1  (cost=0.00..2.00 rows=100 width=4) (actual time=0.006..0.019 rows=100 loops=1)
Planning time: 0.092 ms
Execution time: 0.158 ms
(6 rows)

在這裡我們可以看到 Aggregate 在loops=1時間上是循環的。PostgreSQL 意識到它不是一個相關的子查詢,它只是將其簡化為文字(本質上)。現在讓我們確保它是相關的。

EXPLAIN ANALYZE
SELECT
 x,
 (CASE WHEN x>20 THEN (SELECT sum(f2.x)+f1.x FROM foo AS f2) END)
FROM foo AS f1;

現在你會看到這個計劃

Seq Scan on foo f1  (cost=0.00..228.50 rows=100 width=4) (actual time=0.020..3.210 rows=100 loops=1)
  SubPlan 1
    ->  Aggregate  (cost=2.25..2.26 rows=1 width=4) (actual time=0.038..0.038 rows=1 loops=80)
          ->  Seq Scan on foo f2  (cost=0.00..2.00 rows=100 width=4) (actual time=0.005..0.017 rows=100 loops=80)
Planning time: 0.104 ms
Execution time: 3.272 ms

這裡的關鍵是聚合loops=80本身需要loops=80seq 掃描。

這都是一般性的,但如果沒有您的範例數據或查詢計劃,我只能給出這些。

引用自:https://dba.stackexchange.com/questions/160281