我有这样的查询:
SELECT "cars"."id" FROM de."cars"
WHERE "cars"."sales_state" = 'onsale'
AND (cars.is_disabled IS NOT TRUE)
AND (cars.price >= 35920)
AND (cars.price <= 659880)
AND ("cars"."featuring_score" IS NOT NULL)
ORDER BY
CASE WHEN cars.featuring_score < 'C' THEN 1
WHEN cars.featuring_score = 'C' THEN 2
WHEN cars.featuring_score > 'C' THEN 3
ELSE 4
END,
CASE WHEN cars.au_rating >= 3 THEN 1
WHEN cars.au_rating = 0 THEN 2
WHEN cars.au_rating = 2 THEN 3
WHEN cars.au_rating = 1 THEN 4
ELSE 6
END,
CASE cars.brand
WHEN 'Audi' THEN 1
WHEN 'Alpina' THEN 2
WHEN 'Artega' THEN 3
WHEN 'BMW' THEN 4
WHEN 'Maybach' THEN 5
ELSE 6
END ASC,
CASE WHEN ABS(cars.price - 347900) < cars.price * 0.2 THEN 1
WHEN ABS(cars.price - 347900) < cars.price * 0.4 THEN 2
WHEN ABS(cars.price - 347900) < cars.price * 0.6 THEN 3
ELSE 4
END,
CASE WHEN images_count = 0 OR images_count IS NULL THEN 1
ELSE 0
END,
ABS(cars.price - 347900)
LIMIT 61;
我正在尝试创建一个索引,以使此查询执行得更快。我感到困惑的是,为什么以下两个索引同样快,并且具有相同的exec查询计划:
CREATE INDEX CONCURRENTLY IF NOT EXISTS index_cars_v2
ON de.cars USING btree
(
(price)
)
WHERE sales_state::text = 'onsale'::text
AND is_disabled IS NOT TRUE
AND featuring_score IS NOT NULL
和
CREATE INDEX CONCURRENTLY IF NOT EXISTS index_cars_v2
ON de.cars USING btree
(
(CASE WHEN cars.featuring_score < 'C' THEN 1 WHEN cars.featuring_score = 'C' THEN 2 WHEN cars.featuring_score > 'C' THEN 3 ELSE 4 END),
(CASE WHEN cars.au_rating >= 3 THEN 1 WHEN cars.au_rating = 0 THEN 2 WHEN cars.au_rating = 2 THEN 3 WHEN cars.au_rating = 1 THEN 4 ELSE 6 END),
(price)
)
WHERE sales_state::text = 'onsale'::text
AND is_disabled IS NOT TRUE
AND featuring_score IS NOT NULL
两者都产生如下查询计划:
"Limit (cost=326.63..326.78 rows=61 width=28) (actual time=218.501..218.508 rows=61 loops=1)"
" Output: id, (CASE WHEN ((featuring_score)::text < 'C'::text) THEN 1 WHEN ((featuring_score)::text = 'C'::text) THEN 2 WHEN ((featuring_score)::text > 'C'::text) THEN 3 ELSE 4 END), (CASE WHEN (au_rating >= 3) THEN 1 WHEN (au_rating = 0) THEN 2 WHEN (au_rating = 2) THEN 3 WHEN (au_rating = 1) THEN 4 ELSE 6 END), (CASE brand WHEN 'Audi'::text THEN 1 WHEN 'Alpina'::text THEN 2 WHEN 'Artega'::text THEN 3 WHEN 'BMW'::text THEN 4 WHEN 'Maybach'::text THEN 5 ELSE 6 END), (CASE WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.2)) THEN 1 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.4)) THEN 2 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.6)) THEN 3 ELSE 4 END), (CASE WHEN ((images_count = 0) OR (images_count IS NULL)) THEN 1 ELSE 0 END), (abs((price - 347900)))"
" Buffers: shared hit=60813"
" -> Sort (cost=326.63..327.35 rows=286 width=28) (actual time=218.499..218.501 rows=61 loops=1)"
" Output: id, (CASE WHEN ((featuring_score)::text < 'C'::text) THEN 1 WHEN ((featuring_score)::text = 'C'::text) THEN 2 WHEN ((featuring_score)::text > 'C'::text) THEN 3 ELSE 4 END), (CASE WHEN (au_rating >= 3) THEN 1 WHEN (au_rating = 0) THEN 2 WHEN (au_rating = 2) THEN 3 WHEN (au_rating = 1) THEN 4 ELSE 6 END), (CASE brand WHEN 'Audi'::text THEN 1 WHEN 'Alpina'::text THEN 2 WHEN 'Artega'::text THEN 3 WHEN 'BMW'::text THEN 4 WHEN 'Maybach'::text THEN 5 ELSE 6 END), (CASE WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.2)) THEN 1 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.4)) THEN 2 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.6)) THEN 3 ELSE 4 END), (CASE WHEN ((images_count = 0) OR (images_count IS NULL)) THEN 1 ELSE 0 END), (abs((price - 347900)))"
" Sort Key: (CASE WHEN ((cars.featuring_score)::text < 'C'::text) THEN 1 WHEN ((cars.featuring_score)::text = 'C'::text) THEN 2 WHEN ((cars.featuring_score)::text > 'C'::text) THEN 3 ELSE 4 END), (CASE WHEN (cars.au_rating >= 3) THEN 1 WHEN (cars.au_rating = 0) THEN 2 WHEN (cars.au_rating = 2) THEN 3 WHEN (cars.au_rating = 1) THEN 4 ELSE 6 END), (CASE cars.brand WHEN 'Audi'::text THEN 1 WHEN 'Alpina'::text THEN 2 WHEN 'Artega'::text THEN 3 WHEN 'BMW'::text THEN 4 WHEN 'Maybach'::text THEN 5 ELSE 6 END), (CASE WHEN ((abs((cars.price - 347900)))::numeric < ((cars.price)::numeric * 0.2)) THEN 1 WHEN ((abs((cars.price - 347900)))::numeric < ((cars.price)::numeric * 0.4)) THEN 2 WHEN ((abs((cars.price - 347900)))::numeric < ((cars.price)::numeric * 0.6)) THEN 3 ELSE 4 END), (CASE WHEN ((cars.images_count = 0) OR (cars.images_count IS NULL)) THEN 1 ELSE 0 END), (abs((cars.price - 347900)))"
" Sort Method: top-N heapsort Memory: 33kB"
" Buffers: shared hit=60813"
" -> Index Scan using index_cars_v2 on de.cars (cost=0.42..316.72 rows=286 width=28) (actual time=0.075..205.774 rows=60655 loops=1)"
" Output: id, CASE WHEN ((featuring_score)::text < 'C'::text) THEN 1 WHEN ((featuring_score)::text = 'C'::text) THEN 2 WHEN ((featuring_score)::text > 'C'::text) THEN 3 ELSE 4 END, CASE WHEN (au_rating >= 3) THEN 1 WHEN (au_rating = 0) THEN 2 WHEN (au_rating = 2) THEN 3 WHEN (au_rating = 1) THEN 4 ELSE 6 END, CASE brand WHEN 'Audi'::text THEN 1 WHEN 'Alpina'::text THEN 2 WHEN 'Artega'::text THEN 3 WHEN 'BMW'::text THEN 4 WHEN 'Maybach'::text THEN 5 ELSE 6 END, CASE WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.2)) THEN 1 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.4)) THEN 2 WHEN ((abs((price - 347900)))::numeric < ((price)::numeric * 0.6)) THEN 3 ELSE 4 END, CASE WHEN ((images_count = 0) OR (images_count IS NULL)) THEN 1 ELSE 0 END, abs((price - 347900))"
" Index Cond: ((cars.price >= 35920) AND (cars.price <= 659880))"
" Buffers: shared hit=60813"
"Planning Time: 1.118 ms"
"Execution Time: 218.589 ms"
我希望将CASE WHEN
和featuring_score
上的功能au_rating
语句添加到索引以产生更好的性能,因为索引将根据第一次排序进行预排序标准,但是完全没有区别。是我的假设不成立还是我在索引定义中以某种方式做了错误的事情。
PS。我还尝试过将price
排在索引的最后,这对查询计划也没有任何影响-实际上,我对此也感到困惑...
PPS。我正在运行PostgreSQL 11
答案 0 :(得分:0)
索引必须包含 all ORDER BY
个条目,以便可以用来避免排序:
CREATE INDEX CONCURRENTLY IF NOT EXISTS index_cars_v2
ON de.cars (
(CASE WHEN cars.featuring_score < 'C' THEN 1
WHEN cars.featuring_score = 'C' THEN 2
WHEN cars.featuring_score > 'C' THEN 3
ELSE 4
END),
(CASE WHEN cars.au_rating >= 3 THEN 1
WHEN cars.au_rating = 0 THEN 2
WHEN cars.au_rating = 2 THEN 3
WHEN cars.au_rating = 1 THEN 4
ELSE 6
END),
(CASE cars.brand
WHEN 'Audi' THEN 1
WHEN 'Alpina' THEN 2
WHEN 'Artega' THEN 3
WHEN 'BMW' THEN 4
WHEN 'Maybach' THEN 5
ELSE 6
END),
(CASE WHEN ABS(cars.price - 347900) < cars.price * 0.2 THEN 1
WHEN ABS(cars.price - 347900) < cars.price * 0.4 THEN 2
WHEN ABS(cars.price - 347900) < cars.price * 0.6 THEN 3
ELSE 4
END),
(CASE WHEN images_count = 0 OR images_count IS NULL THEN 1
ELSE 0
END),
(ABS(cars.price - 347900))
WHERE sales_state = 'onsale'
AND is_disabled IS NOT TRUE
AND featuring_score IS NOT NULL;