PostgreSQL:在查询中使用许多 OR 条件时出现脏块
PostgreSQL: Dirtied blocks when using many OR conditions in query
我正在使用 PostgreSQL 13.7。
在尝试优化由多个子查询组成的查询时,我注意到减少最后部分中的 OR 子句数量可以显着提高性能(800 毫秒到 70 毫秒)。有问题的部分是这样的(只有一部分,完整的查询和分析报告将在最后添加):
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR setdiscount_limitval > 0
OR setdiscounteffect_limitval > 0
OR customeffect_limitval > 0
OR createloyaltypoints_limitval > 0
OR createloyaltypointseffect_limitval > 0
OR redeemloyaltypoints_limitval > 0
OR redeemloyaltypointseffect_limitval > 0
OR callapi_limitval > 0
OR awardgiveaway_limitval > 0
OR addfreeitemeffect_limitval > 0);
请注意,limit_actions
是只有几行的子查询的结果。
最后一部分是为了不获取不必要的行并节省数据传输而添加的一种优化。一旦我将 OR 条件的数量减少到 4 个或更少,我就看到了巨大的改进。
EXPLAIN ANALYZing 两个变体表明,只要有超过 4 个 OR 子句,查询就会导致脏块。主要区别在于:
More than 4 OR clauses:
Shared Hit Blocks 113
Shared Read Blocks 163
Shared Dirtied Blocks 65
--------------------------------
4 OR clauses or less:
Shared Hit Blocks 259
Shared Read Blocks 0
Shared Dirtied Blocks 0
我想了解发生这种情况的方式和原因。特别是 OR 子句如何产生这样的效果。根据我有限的理解,脏块意味着无效的缓存。对吗?
这是我为完整性而执行的整个查询:
EXPLAIN (ANALYZE,
COSTS,
VERBOSE,
BUFFERS
)
WITH campaign_limits AS (
SELECT
id,
action,
campaignid,
couponid,
referralid,
profileid,
counter,
limitval,
identifier
FROM
limit_counters
WHERE
campaignid IN(789, 793, 726, 727, 890, 790, 785, 794, 781, 786, 792, 832, 772, 903, 992, 791, 787, 771, 963, 784, 775, 776, 779, 926, 749, 889, 1010, 1011, 788, 783, 782, 984, 780, 396, 725, 445, 773, 763, 770, 778, 993, 1019, 1021, 1022)
AND couponid IS NULL
AND identifier IS NULL
AND profileid IS NULL
AND referralid IS NULL
ORDER BY
action ASC), -- O(rows*)
limits_actions AS (
SELECT
campaignid,
sum(
CASE WHEN action = 'createCoupon' THEN
limitval
ELSE
0
END) AS createcoupon_limitval,
sum(
CASE WHEN action = 'createCoupon' THEN
counter
ELSE
0
END) AS createcoupon_counter,
sum(
CASE WHEN action = 'createReferral' THEN
limitval
ELSE
0
END) AS createreferral_limitval,
sum(
CASE WHEN action = 'createReferral' THEN
counter
ELSE
0
END) AS createreferral_counter,
sum(
CASE WHEN action = 'redeemCoupon' THEN
limitval
ELSE
0
END) AS redeemcoupon_limitval,
sum(
CASE WHEN action = 'redeemCoupon' THEN
counter
ELSE
0
END) AS redeemcoupon_counter,
sum(
CASE WHEN action = 'redeemReferral' THEN
limitval
ELSE
0
END) AS redeemreferral_limitval,
sum(
CASE WHEN action = 'redeemReferral' THEN
counter
ELSE
0
END) AS redeemreferral_counter,
sum(
CASE WHEN action = 'setDiscount' THEN
limitval
ELSE
0
END) AS setdiscount_limitval,
sum(
CASE WHEN action = 'setDiscount' THEN
counter
ELSE
0
END) AS setdiscount_counter,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
limitval
ELSE
0
END) AS setdiscounteffect_limitval,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
counter
ELSE
0
END) AS setdiscounteffect_counter,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
limitval
ELSE
0
END) AS createloyaltypoints_limitval,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
counter
ELSE
0
END) AS createloyaltypoints_counter,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS createloyaltypointseffect_limitval,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS createloyaltypointseffect_counter,
sum(
CASE WHEN action = 'customEffect' THEN
limitval
ELSE
0
END) AS customeffect_limitval,
sum(
CASE WHEN action = 'customEffect' THEN
counter
ELSE
0
END) AS customeffect_counter,
sum(
CASE WHEN action = 'callApi' THEN
limitval
ELSE
0
END) AS callapi_limitval, sum(
CASE WHEN action = 'callApi' THEN
counter
ELSE
0
END) AS callapi_counter, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
limitval
ELSE
0
END) AS redeemloyaltypoints_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
counter
ELSE
0
END) AS redeemloyaltypoints_counter, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS redeemloyaltypointseffect_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS redeemloyaltypointseffect_counter, sum(
CASE WHEN action = 'awardGiveaway' THEN
limitval
ELSE
0
END) AS awardgiveaway_limitval, sum(
CASE WHEN action = 'awardGiveaway' THEN
counter
ELSE
0
END) AS awardgiveaway_counter, sum(
CASE WHEN action = 'addFreeItem' THEN
limitval
ELSE
0
END) AS addfreeitemeffect_limitval, sum(
CASE WHEN action = 'addFreeItem' THEN
counter
ELSE
0
END) AS addfreeitemeffect_counter
FROM
campaign_limits
GROUP BY
campaignid
)
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR setdiscount_limitval > 0
OR setdiscounteffect_limitval > 0
OR customeffect_limitval > 0
OR createloyaltypoints_limitval > 0
OR createloyaltypointseffect_limitval > 0
OR redeemloyaltypoints_limitval > 0
OR redeemloyaltypointseffect_limitval > 0
OR callapi_limitval > 0
OR awardgiveaway_limitval > 0
OR addfreeitemeffect_limitval > 0);
分析结果:
HashAggregate (cost=542192.34..542207.69 rows=340 width=232) (actual time=759.467..759.502 rows=41 loops=1)
" Output: limit_counters.campaignid, sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.counter ELSE '0'::double precision END)"
Group Key: limit_counters.campaignid
" Filter: ((sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision))"
Batches: 1 Memory Usage: 61kB
Rows Removed by Filter: 3
Buffers: shared hit=270
-> Sort (cost=331926.02..334262.31 rows=934517 width=97) (actual time=759.062..759.086 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
Sort Key: limit_counters.action
Sort Method: quicksort Memory: 53kB
Buffers: shared hit=270
-> Index Scan using limit_counters_non_nulls_campaignid_idx on public.limit_counters (cost=0.28..210046.61 rows=934517 width=97) (actual time=758.530..758.895 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
" Index Cond: (limit_counters.campaignid = ANY ('{789,793,726,727,890,790,785,794,781,786,792,832,772,903,992,791,787,771,963,784,775,776,779,926,749,889,1010,1011,788,783,782,984,780,396,725,445,773,763,770,778,993,1019,1021,1022}'::bigint[]))"
Buffers: shared hit=270
Planning:
Buffers: shared hit=1
Planning Time: 0.707 ms
JIT:
Functions: 12
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 5.870 ms, Inlining 16.245 ms, Optimization 378.807 ms, Emission 363.469 ms, Total 764.391 ms
Execution Time: 765.627 ms
下面是相同的查询,但删除了一些最后的 OR 子句:
EXPLAIN (ANALYZE,
COSTS,
VERBOSE,
BUFFERS
)
WITH campaign_limits AS (
SELECT
id,
action,
campaignid,
couponid,
referralid,
profileid,
counter,
limitval,
identifier
FROM
limit_counters
WHERE
campaignid IN(789, 793, 726, 727, 890, 790, 785, 794, 781, 786, 792, 832, 772, 903, 992, 791, 787, 771, 963, 784, 775, 776, 779, 926, 749, 889, 1010, 1011, 788, 783, 782, 984, 780, 396, 725, 445, 773, 763, 770, 778, 993, 1019, 1021, 1022)
AND couponid IS NULL
AND identifier IS NULL
AND profileid IS NULL
AND referralid IS NULL
ORDER BY
action ASC),
limits_actions AS (
SELECT
campaignid,
sum(
CASE WHEN action = 'createCoupon' THEN
limitval
ELSE
0
END) AS createcoupon_limitval,
sum(
CASE WHEN action = 'createCoupon' THEN
counter
ELSE
0
END) AS createcoupon_counter,
sum(
CASE WHEN action = 'createReferral' THEN
limitval
ELSE
0
END) AS createreferral_limitval,
sum(
CASE WHEN action = 'createReferral' THEN
counter
ELSE
0
END) AS createreferral_counter,
sum(
CASE WHEN action = 'redeemCoupon' THEN
limitval
ELSE
0
END) AS redeemcoupon_limitval,
sum(
CASE WHEN action = 'redeemCoupon' THEN
counter
ELSE
0
END) AS redeemcoupon_counter,
sum(
CASE WHEN action = 'redeemReferral' THEN
limitval
ELSE
0
END) AS redeemreferral_limitval,
sum(
CASE WHEN action = 'redeemReferral' THEN
counter
ELSE
0
END) AS redeemreferral_counter,
sum(
CASE WHEN action = 'setDiscount' THEN
limitval
ELSE
0
END) AS setdiscount_limitval,
sum(
CASE WHEN action = 'setDiscount' THEN
counter
ELSE
0
END) AS setdiscount_counter,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
limitval
ELSE
0
END) AS setdiscounteffect_limitval,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
counter
ELSE
0
END) AS setdiscounteffect_counter,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
limitval
ELSE
0
END) AS createloyaltypoints_limitval,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
counter
ELSE
0
END) AS createloyaltypoints_counter,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS createloyaltypointseffect_limitval,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS createloyaltypointseffect_counter,
sum(
CASE WHEN action = 'customEffect' THEN
limitval
ELSE
0
END) AS customeffect_limitval,
sum(
CASE WHEN action = 'customEffect' THEN
counter
ELSE
0
END) AS customeffect_counter,
sum(
CASE WHEN action = 'callApi' THEN
limitval
ELSE
0
END) AS callapi_limitval, sum(
CASE WHEN action = 'callApi' THEN
counter
ELSE
0
END) AS callapi_counter, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
limitval
ELSE
0
END) AS redeemloyaltypoints_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
counter
ELSE
0
END) AS redeemloyaltypoints_counter, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS redeemloyaltypointseffect_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS redeemloyaltypointseffect_counter, sum(
CASE WHEN action = 'awardGiveaway' THEN
limitval
ELSE
0
END) AS awardgiveaway_limitval, sum(
CASE WHEN action = 'awardGiveaway' THEN
counter
ELSE
0
END) AS awardgiveaway_counter, sum(
CASE WHEN action = 'addFreeItem' THEN
limitval
ELSE
0
END) AS addfreeitemeffect_limitval, sum(
CASE WHEN action = 'addFreeItem' THEN
counter
ELSE
0
END) AS addfreeitemeffect_counter
FROM
campaign_limits
GROUP BY
campaignid
)
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR createreferral_limitval > 0
OR redeemreferral_limitval > 0);
分析结果:
HashAggregate (cost=495466.49..495473.31 rows=274 width=232) (actual time=46.782..46.817 rows=38 loops=1)
" Output: limit_counters.campaignid, sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.counter ELSE '0'::double precision END)"
Group Key: limit_counters.campaignid
" Filter: ((sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision))"
Batches: 1 Memory Usage: 61kB
Rows Removed by Filter: 6
Buffers: shared hit=270
-> Sort (cost=331926.02..334262.31 rows=934517 width=97) (actual time=46.287..46.310 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
Sort Key: limit_counters.action
Sort Method: quicksort Memory: 53kB
Buffers: shared hit=270
-> Index Scan using limit_counters_non_nulls_campaignid_idx on public.limit_counters (cost=0.28..210046.61 rows=934517 width=97) (actual time=45.651..46.120 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
" Index Cond: (limit_counters.campaignid = ANY ('{789,793,726,727,890,790,785,794,781,786,792,832,772,903,992,791,787,771,963,784,775,776,779,926,749,889,1010,1011,788,783,782,984,780,396,725,445,773,763,770,778,993,1019,1021,1022}'::bigint[]))"
Buffers: shared hit=270
Planning:
Buffers: shared hit=1
Planning Time: 0.630 ms
JIT:
Functions: 12
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 5.904 ms, Inlining 0.000 ms, Optimization 1.310 ms, Emission 44.317 ms, Total 51.531 ms
Execution Time: 52.933 ms
您性能的真正问题是 just-in-time 编译。它在两个查询中都占据了您的 运行 时间。关闭 jit。那如果你还有问题,post关闭jit后的新计划。 (计划可能不会改变,但时间会改变)。
此外,按两个顺序重复查询几次。看起来第二个查询更快仅仅是因为第一个查询用第二个查询需要的数据预热缓存。 OR 子句的数量可能与此无关,只是您碰巧按特定顺序 运行 它们。第一个不仅预热缓存,而且还设置提示位(这是导致脏页的原因)。它似乎也会加热 JIT 功能所依赖的任何缓存(据我所知,这不在 PostgreSQL 的控制之下)
我正在使用 PostgreSQL 13.7。
在尝试优化由多个子查询组成的查询时,我注意到减少最后部分中的 OR 子句数量可以显着提高性能(800 毫秒到 70 毫秒)。有问题的部分是这样的(只有一部分,完整的查询和分析报告将在最后添加):
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR setdiscount_limitval > 0
OR setdiscounteffect_limitval > 0
OR customeffect_limitval > 0
OR createloyaltypoints_limitval > 0
OR createloyaltypointseffect_limitval > 0
OR redeemloyaltypoints_limitval > 0
OR redeemloyaltypointseffect_limitval > 0
OR callapi_limitval > 0
OR awardgiveaway_limitval > 0
OR addfreeitemeffect_limitval > 0);
请注意,limit_actions
是只有几行的子查询的结果。
最后一部分是为了不获取不必要的行并节省数据传输而添加的一种优化。一旦我将 OR 条件的数量减少到 4 个或更少,我就看到了巨大的改进。
EXPLAIN ANALYZing 两个变体表明,只要有超过 4 个 OR 子句,查询就会导致脏块。主要区别在于:
More than 4 OR clauses:
Shared Hit Blocks 113
Shared Read Blocks 163
Shared Dirtied Blocks 65
--------------------------------
4 OR clauses or less:
Shared Hit Blocks 259
Shared Read Blocks 0
Shared Dirtied Blocks 0
我想了解发生这种情况的方式和原因。特别是 OR 子句如何产生这样的效果。根据我有限的理解,脏块意味着无效的缓存。对吗?
这是我为完整性而执行的整个查询:
EXPLAIN (ANALYZE,
COSTS,
VERBOSE,
BUFFERS
)
WITH campaign_limits AS (
SELECT
id,
action,
campaignid,
couponid,
referralid,
profileid,
counter,
limitval,
identifier
FROM
limit_counters
WHERE
campaignid IN(789, 793, 726, 727, 890, 790, 785, 794, 781, 786, 792, 832, 772, 903, 992, 791, 787, 771, 963, 784, 775, 776, 779, 926, 749, 889, 1010, 1011, 788, 783, 782, 984, 780, 396, 725, 445, 773, 763, 770, 778, 993, 1019, 1021, 1022)
AND couponid IS NULL
AND identifier IS NULL
AND profileid IS NULL
AND referralid IS NULL
ORDER BY
action ASC), -- O(rows*)
limits_actions AS (
SELECT
campaignid,
sum(
CASE WHEN action = 'createCoupon' THEN
limitval
ELSE
0
END) AS createcoupon_limitval,
sum(
CASE WHEN action = 'createCoupon' THEN
counter
ELSE
0
END) AS createcoupon_counter,
sum(
CASE WHEN action = 'createReferral' THEN
limitval
ELSE
0
END) AS createreferral_limitval,
sum(
CASE WHEN action = 'createReferral' THEN
counter
ELSE
0
END) AS createreferral_counter,
sum(
CASE WHEN action = 'redeemCoupon' THEN
limitval
ELSE
0
END) AS redeemcoupon_limitval,
sum(
CASE WHEN action = 'redeemCoupon' THEN
counter
ELSE
0
END) AS redeemcoupon_counter,
sum(
CASE WHEN action = 'redeemReferral' THEN
limitval
ELSE
0
END) AS redeemreferral_limitval,
sum(
CASE WHEN action = 'redeemReferral' THEN
counter
ELSE
0
END) AS redeemreferral_counter,
sum(
CASE WHEN action = 'setDiscount' THEN
limitval
ELSE
0
END) AS setdiscount_limitval,
sum(
CASE WHEN action = 'setDiscount' THEN
counter
ELSE
0
END) AS setdiscount_counter,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
limitval
ELSE
0
END) AS setdiscounteffect_limitval,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
counter
ELSE
0
END) AS setdiscounteffect_counter,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
limitval
ELSE
0
END) AS createloyaltypoints_limitval,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
counter
ELSE
0
END) AS createloyaltypoints_counter,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS createloyaltypointseffect_limitval,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS createloyaltypointseffect_counter,
sum(
CASE WHEN action = 'customEffect' THEN
limitval
ELSE
0
END) AS customeffect_limitval,
sum(
CASE WHEN action = 'customEffect' THEN
counter
ELSE
0
END) AS customeffect_counter,
sum(
CASE WHEN action = 'callApi' THEN
limitval
ELSE
0
END) AS callapi_limitval, sum(
CASE WHEN action = 'callApi' THEN
counter
ELSE
0
END) AS callapi_counter, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
limitval
ELSE
0
END) AS redeemloyaltypoints_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
counter
ELSE
0
END) AS redeemloyaltypoints_counter, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS redeemloyaltypointseffect_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS redeemloyaltypointseffect_counter, sum(
CASE WHEN action = 'awardGiveaway' THEN
limitval
ELSE
0
END) AS awardgiveaway_limitval, sum(
CASE WHEN action = 'awardGiveaway' THEN
counter
ELSE
0
END) AS awardgiveaway_counter, sum(
CASE WHEN action = 'addFreeItem' THEN
limitval
ELSE
0
END) AS addfreeitemeffect_limitval, sum(
CASE WHEN action = 'addFreeItem' THEN
counter
ELSE
0
END) AS addfreeitemeffect_counter
FROM
campaign_limits
GROUP BY
campaignid
)
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR setdiscount_limitval > 0
OR setdiscounteffect_limitval > 0
OR customeffect_limitval > 0
OR createloyaltypoints_limitval > 0
OR createloyaltypointseffect_limitval > 0
OR redeemloyaltypoints_limitval > 0
OR redeemloyaltypointseffect_limitval > 0
OR callapi_limitval > 0
OR awardgiveaway_limitval > 0
OR addfreeitemeffect_limitval > 0);
分析结果:
HashAggregate (cost=542192.34..542207.69 rows=340 width=232) (actual time=759.467..759.502 rows=41 loops=1)
" Output: limit_counters.campaignid, sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.counter ELSE '0'::double precision END)"
Group Key: limit_counters.campaignid
" Filter: ((sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision))"
Batches: 1 Memory Usage: 61kB
Rows Removed by Filter: 3
Buffers: shared hit=270
-> Sort (cost=331926.02..334262.31 rows=934517 width=97) (actual time=759.062..759.086 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
Sort Key: limit_counters.action
Sort Method: quicksort Memory: 53kB
Buffers: shared hit=270
-> Index Scan using limit_counters_non_nulls_campaignid_idx on public.limit_counters (cost=0.28..210046.61 rows=934517 width=97) (actual time=758.530..758.895 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
" Index Cond: (limit_counters.campaignid = ANY ('{789,793,726,727,890,790,785,794,781,786,792,832,772,903,992,791,787,771,963,784,775,776,779,926,749,889,1010,1011,788,783,782,984,780,396,725,445,773,763,770,778,993,1019,1021,1022}'::bigint[]))"
Buffers: shared hit=270
Planning:
Buffers: shared hit=1
Planning Time: 0.707 ms
JIT:
Functions: 12
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 5.870 ms, Inlining 16.245 ms, Optimization 378.807 ms, Emission 363.469 ms, Total 764.391 ms
Execution Time: 765.627 ms
下面是相同的查询,但删除了一些最后的 OR 子句:
EXPLAIN (ANALYZE,
COSTS,
VERBOSE,
BUFFERS
)
WITH campaign_limits AS (
SELECT
id,
action,
campaignid,
couponid,
referralid,
profileid,
counter,
limitval,
identifier
FROM
limit_counters
WHERE
campaignid IN(789, 793, 726, 727, 890, 790, 785, 794, 781, 786, 792, 832, 772, 903, 992, 791, 787, 771, 963, 784, 775, 776, 779, 926, 749, 889, 1010, 1011, 788, 783, 782, 984, 780, 396, 725, 445, 773, 763, 770, 778, 993, 1019, 1021, 1022)
AND couponid IS NULL
AND identifier IS NULL
AND profileid IS NULL
AND referralid IS NULL
ORDER BY
action ASC),
limits_actions AS (
SELECT
campaignid,
sum(
CASE WHEN action = 'createCoupon' THEN
limitval
ELSE
0
END) AS createcoupon_limitval,
sum(
CASE WHEN action = 'createCoupon' THEN
counter
ELSE
0
END) AS createcoupon_counter,
sum(
CASE WHEN action = 'createReferral' THEN
limitval
ELSE
0
END) AS createreferral_limitval,
sum(
CASE WHEN action = 'createReferral' THEN
counter
ELSE
0
END) AS createreferral_counter,
sum(
CASE WHEN action = 'redeemCoupon' THEN
limitval
ELSE
0
END) AS redeemcoupon_limitval,
sum(
CASE WHEN action = 'redeemCoupon' THEN
counter
ELSE
0
END) AS redeemcoupon_counter,
sum(
CASE WHEN action = 'redeemReferral' THEN
limitval
ELSE
0
END) AS redeemreferral_limitval,
sum(
CASE WHEN action = 'redeemReferral' THEN
counter
ELSE
0
END) AS redeemreferral_counter,
sum(
CASE WHEN action = 'setDiscount' THEN
limitval
ELSE
0
END) AS setdiscount_limitval,
sum(
CASE WHEN action = 'setDiscount' THEN
counter
ELSE
0
END) AS setdiscount_counter,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
limitval
ELSE
0
END) AS setdiscounteffect_limitval,
sum(
CASE WHEN action = 'setDiscountEffect' THEN
counter
ELSE
0
END) AS setdiscounteffect_counter,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
limitval
ELSE
0
END) AS createloyaltypoints_limitval,
sum(
CASE WHEN action = 'createLoyaltyPoints' THEN
counter
ELSE
0
END) AS createloyaltypoints_counter,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS createloyaltypointseffect_limitval,
sum(
CASE WHEN action = 'createLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS createloyaltypointseffect_counter,
sum(
CASE WHEN action = 'customEffect' THEN
limitval
ELSE
0
END) AS customeffect_limitval,
sum(
CASE WHEN action = 'customEffect' THEN
counter
ELSE
0
END) AS customeffect_counter,
sum(
CASE WHEN action = 'callApi' THEN
limitval
ELSE
0
END) AS callapi_limitval, sum(
CASE WHEN action = 'callApi' THEN
counter
ELSE
0
END) AS callapi_counter, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
limitval
ELSE
0
END) AS redeemloyaltypoints_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPoints' THEN
counter
ELSE
0
END) AS redeemloyaltypoints_counter, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
limitval
ELSE
0
END) AS redeemloyaltypointseffect_limitval, sum(
CASE WHEN action = 'redeemLoyaltyPointsEffect' THEN
counter
ELSE
0
END) AS redeemloyaltypointseffect_counter, sum(
CASE WHEN action = 'awardGiveaway' THEN
limitval
ELSE
0
END) AS awardgiveaway_limitval, sum(
CASE WHEN action = 'awardGiveaway' THEN
counter
ELSE
0
END) AS awardgiveaway_counter, sum(
CASE WHEN action = 'addFreeItem' THEN
limitval
ELSE
0
END) AS addfreeitemeffect_limitval, sum(
CASE WHEN action = 'addFreeItem' THEN
counter
ELSE
0
END) AS addfreeitemeffect_counter
FROM
campaign_limits
GROUP BY
campaignid
)
SELECT
*
FROM
limits_actions
WHERE (createcoupon_limitval > 0
OR redeemcoupon_limitval > 0
OR createreferral_limitval > 0
OR redeemreferral_limitval > 0);
分析结果:
HashAggregate (cost=495466.49..495473.31 rows=274 width=232) (actual time=46.782..46.817 rows=38 loops=1)
" Output: limit_counters.campaignid, sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscount'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'setDiscountEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'createLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'customEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'callApi'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPoints'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'redeemLoyaltyPointsEffect'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'awardGiveaway'::text) THEN limit_counters.counter ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.limitval ELSE '0'::double precision END), sum(CASE WHEN (limit_counters.action = 'addFreeItem'::text) THEN limit_counters.counter ELSE '0'::double precision END)"
Group Key: limit_counters.campaignid
" Filter: ((sum(CASE WHEN (limit_counters.action = 'createCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemCoupon'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'createReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision) OR (sum(CASE WHEN (limit_counters.action = 'redeemReferral'::text) THEN limit_counters.limitval ELSE '0'::double precision END) > '0'::double precision))"
Batches: 1 Memory Usage: 61kB
Rows Removed by Filter: 6
Buffers: shared hit=270
-> Sort (cost=331926.02..334262.31 rows=934517 width=97) (actual time=46.287..46.310 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
Sort Key: limit_counters.action
Sort Method: quicksort Memory: 53kB
Buffers: shared hit=270
-> Index Scan using limit_counters_non_nulls_campaignid_idx on public.limit_counters (cost=0.28..210046.61 rows=934517 width=97) (actual time=45.651..46.120 rows=300 loops=1)
Output: NULL::integer, limit_counters.action, limit_counters.campaignid, NULL::bigint, NULL::bigint, NULL::bigint, limit_counters.counter, limit_counters.limitval, NULL::text
" Index Cond: (limit_counters.campaignid = ANY ('{789,793,726,727,890,790,785,794,781,786,792,832,772,903,992,791,787,771,963,784,775,776,779,926,749,889,1010,1011,788,783,782,984,780,396,725,445,773,763,770,778,993,1019,1021,1022}'::bigint[]))"
Buffers: shared hit=270
Planning:
Buffers: shared hit=1
Planning Time: 0.630 ms
JIT:
Functions: 12
Options: Inlining false, Optimization false, Expressions true, Deforming true
Timing: Generation 5.904 ms, Inlining 0.000 ms, Optimization 1.310 ms, Emission 44.317 ms, Total 51.531 ms
Execution Time: 52.933 ms
您性能的真正问题是 just-in-time 编译。它在两个查询中都占据了您的 运行 时间。关闭 jit。那如果你还有问题,post关闭jit后的新计划。 (计划可能不会改变,但时间会改变)。
此外,按两个顺序重复查询几次。看起来第二个查询更快仅仅是因为第一个查询用第二个查询需要的数据预热缓存。 OR 子句的数量可能与此无关,只是您碰巧按特定顺序 运行 它们。第一个不仅预热缓存,而且还设置提示位(这是导致脏页的原因)。它似乎也会加热 JIT 功能所依赖的任何缓存(据我所知,这不在 PostgreSQL 的控制之下)