POSTGRESQL SQL 语句案例,一场由LIMIT 1 引发的“奇怪异像”
创始人
2024-05-29 14:22:15
0

开头还是介绍一下群,如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题,有需求都可以加群群内有各大数据库行业大咖,CTO,可以解决你的问题。加群请联系 liuaustin3 ,在新加的朋友会分到2群。

fdb35d07a21c46d1442e506c97735e9d.png

最近一段工作很少优化SQL ,实际

上7-8年前的确有一段疯狂优化的“美好时光”。 最近一个同事提出一个问题,他的一个POSTGRESQL 的SQL 在运行中因为客户的需要,将语句添加limit 1 ,但是在添加完毕后,整体语句运行时间超过原有的语句少则9倍,多则20多倍,从不到2秒,变成了23秒。

下面是语句的修改版,不少部分已经改名了。

SELECT

bizzz.* 

FROM

(

SELECT

1 AS "bizzzType",

os.NAME "deFromName",

gb.title "ticketName",

gb.market_price "marketPrice",

gb.price price,

gb.discount_rate * 100 "discountRate",

gb.income_money "ticketIncomeMoney",

gb.div_ticket_name "divTicketName",

btpg.ticket_count "ticketCount",

btpg.pay_money "payMoney",

( gb.market_price - gb.price ) * btpg.ticket_count "discMoney",

CASE 

WHEN btpg.ticket_sale * btpg.ticket_count > btpg.pay_money 

THEN

btpg.pay_money 

ELSE btpg.ticket_sale * btpg.ticket_count 

END "incomeMoney",

shop.ID AS "shopId",

shop.NAME AS "shopName",

btpg.no_give_change "noGiveChange",

btpg.bs_id "bsId",

bb.code "bsCode",

btpg.ticket_code "ticketCode",

btpg.create_time "useTime",

bb.settle_bizzz_date "settlebizzzDate",

COALESCE ( btpg.income_overchange, 0 ) "incomeOverChange" ,

pw_detail_id as "ticketRowId"

FROM

(SELECT

bs_id,

ticket_count,

ticket_sale,

ticket_value,

pay_money,

payc_id,

ticket_id,

create_shop_id,

pw_detail_id,

no_give_change,

create_time,

REPLACE ( REPLACE ( REPLACE ( REPLACE ( ticket_code_serials, '["', '' ), '"]', '' ), '"', '' ), ',', ';' ) AS ticket_code,

income_overchange 

FROM  bizzz_ts_pw_gb 

WHERE create_shop_id IN ( SELECT ID FROM dbi_shop WHERE center_id = 83726 AND manage_type_id IN ( 301, 302, 304 ) ) 

AND modify_time >= '2023-03-02 00:00:00' 

AND modify_time <'2023-03-03 00:00:00' 

AND delflg = 0 

AND settle_state = 1 

) btpg

INNER JOIN (SELECT ID,code,settle_bizzz_date  FROM

bizzz_bs 

WHERE

create_shop_id IN ( SELECT ID FROM dbi_shop WHERE center_id = 83726 AND manage_type_id IN ( 301, 302, 304 ) ) AND settle_time >='2023-03-02 00:00:00'  AND settle_time < '2023-03-03 00:00:00'AND STATE = 1 

AND delflg = 0 ) bb ON btpg.bs_id = bb.

ID

INNER JOIN ( SELECT ID FROM arch_pay c WHERE payc_type_id = 509 ) ap ON btpg.payc_id = ap.ID

LEFT JOIN ( SELECT deal_id, belong_shop_id, title, market_price, price, discount_rate, income_money, synchron_time, div_ticket_name 

FROM o2o_wuu_gb_ticket 

WHERE create_shop_id = 83726 ) gb ON btpg.ticket_id = gb.deal_id AND btpg.create_shop_id = gb.belong_shop_id

INNER JOIN ( SELECT deal_id, belong_shop_id, MAX ( synchron_time ) synchron_time 

FROM o2o_wuu_gb_ticket 

WHERE create_shop_id = 83726 GROUP BY belong_shop_id, deal_id ) gbTicketFilter ON gb.deal_id = gbTicketFilter.deal_id 

AND gb.belong_shop_id = gbTicketFilter.belong_shop_id AND gb.synchron_time = gbTicketFilter.synchron_time

INNER JOIN ( SELECT payc_id, NAME FROM arch_o2o_seller ) os ON os.payc_id = btpg.payc_id

LEFT JOIN dbi_shop shop ON shop.ID = btpg.create_shop_id 

) bizzz 

ORDER BY

"shopName","ticketName","marketPrice","ticketRowId";

 limit 1;

首先比对执行计划,虽然仅仅是一个limit 的添加但是整体的执行计划都改变了,

3c72236aad842f6f8c639d662063ca88.png

改变发现1 

在没有添加LIMIT 1的情况下,整体的语句的查询中是没有 大量的seq scan ,基本上整体整体的语句中对于数据处理都是在index scan.

改变发现2 

在添加LIMIT 1 后,整体的语句的执行顺序,与原先的顺序不同了,不添加limit  1  ,首先处理了语句中最大的表,由于最大的表的数据过滤的条件多,所以对于排除数据起到了相关的提前过滤的作用。

而添加了limit 1后,整体的语句处理的顺序和语句撰写的从上到下的语句关联的顺序基本一致,导致处理从小表开始进行预先处理。最终导致小表驱动大表的情况。

改变发现3

在不添加LIMIT 1 的情况下,整体上层的 语句中的计算部分使用中由于,执行顺序的问题,让大表的数据过滤后,在被上层使用,减少了计算的数据量,而反观添加了LIMIT 1 后的语句,计算中过滤的行较多。导致计算成本升高。

sort  的部分中的语句执行的整体计划的顺序,与加入了limit 的整体计划的顺序是错位的。

SORT 没有limit 的部分,中的驱动表与驱动表之间是通过index 关联的方式进行的处理。

fc39cb5fbca225e68cb931fad95c3926.png

limit   而在末尾加入了limit 后,整体的执行计划,驱动表和被驱动表的位置互换了,通知对于驱动表的执行的方式变为了扫描方式。

fc42f5c3c726f922781c10803bbcddbf.png

由于语句是否的复杂,如果要非常的明白的分析出来,则需要很长的时间,实际上抓住了两点

1 复杂的语句如果使用了limit 1,需要注意在POSTGRESQL 13中的语句是否还能通过优化器,优先判断对数据进行大表过滤,由于使用LIMIT 1 这样的语句,导致语句优化和执行系统对于提取的数据的有序性判断过于复杂,导致优化器,按照语句的撰写方式进行了数据的执行,保证提取数据的优秀和有效性,同时多个不同表的字段最终进行排序,加重了执行分析器的负担,导致执行分析器躺平,做了保守的执行计划的操作。

2  业务逻辑是否需要对于LIMIT 1 的语句进行排序的分析,这点非常有必要,在语句的执行中大部分语句的撰写尤其类似这样OLAP 很重的语句一般都带有排序,但是如果只是在结果中取一个结果  limit 1 则是否有必要进行排序这点非常有必要进行确认。一般根据语句的逻辑,是没有必要进行排序在LIMIT 1,因为你是随机取和顺序是无关的。

这个语句实际上最后优化的手段就是去掉ORDER BY ,最终去掉后比原先的同样的条件,执行的效率提高了  62倍,在 150毫秒左右就将结果计算出来,同时还有一个因素是如果你在撰写语句的时候带有LIMIT 1 则POSTGRESQL 的优化器会优先选择计算成本中,第一个启动成本较低的执行计划而不是整体成本较低的执行计划,所以建议在一些语句中,考虑业务的需求的情况下,分析是否有必要进行排序,慎用在复杂语句中的排序导致的执行效率低下的问题。

另外这里还有一个在使用LIMIT 1 后导致的PG执行计划的倾向性的问题,你造吗 !

181c7c700dd245e4a153a218c53b2f9b.png

48f93969e31d1cd5c1b10670235784bb.png

4a1c4d3562afd623df693ebce9b3ff2b.png

相关内容

热门资讯

Python|位运算|数组|动... 目录 1、只出现一次的数字(位运算,数组) 示例 选项代...
张岱的人物生平 张岱的人物生平张岱(414年-484年),字景山,吴郡吴县(今江苏苏州)人。南朝齐大臣。祖父张敞,东...
西游西后传演员女人物 西游西后传演员女人物西游西后传演员女人物 孙悟空 六小龄童 唐僧 徐少华 ...
名人故事中贾岛作诗内容简介 名人故事中贾岛作诗内容简介有一次,贾岛骑驴闯了官道.他正琢磨着一句诗,名叫《题李凝幽居》全诗如下:闲...
和男朋友一起优秀的文案? 和男朋友一起优秀的文案?1.希望是惟一所有的人都共同享有的好处;一无所有的人,仍拥有希望。2.生活,...
戴玉手镯的好处 戴玉手镯好还是... 戴玉手镯的好处 戴玉手镯好还是碧玺好 女人戴玉?戴玉好还是碧玺好点佩戴手镯,以和田玉手镯为佳!相嫌滑...
依然什么意思? 依然什么意思?依然(汉语词语)依然,汉语词汇。拼音:yī    rán基本解释:副词,指照往常、依旧...
高尔基的散文诗 高尔基的散文诗《海燕》、《大学》、《母亲》、《童年》这些都是比较出名的一些代表作。
心在飞扬作者简介 心在飞扬作者简介心在飞扬作者简介如下。根据相关公开资料查询,心在飞扬是一位优秀的小说作者,他的小说作...
卡什坦卡的故事赏析? 卡什坦卡的故事赏析?讲了一只小狗的故事, 我也是近来才读到这篇小说. 作家对动物的拟人描写真是惟妙...
林绍涛为简艾拿绿豆糕是哪一集 林绍涛为简艾拿绿豆糕是哪一集第三十二集。 贾宽认为是阎帅间接导致刘映霞住了院,第二天上班,他按捺不...
小爱同学是女生吗小安同学什么意... 小爱同学是女生吗小安同学什么意思 小爱同学,小安同学说你是女生。小安是男的。
内分泌失调导致脸上长斑,怎么调... 内分泌失调导致脸上长斑,怎么调理内分泌失调导致脸上长斑,怎么调理先调理内分泌,去看中医吧,另外用好的...
《魔幻仙境》刺客,骑士人物属性... 《魔幻仙境》刺客,骑士人物属性加点魔幻仙境骑士2功1体质
很喜欢她,该怎么办? 很喜欢她,该怎么办?太冷静了!! 太理智了!爱情是需要冲劲的~不要考虑着考虑那~否则缘...
言情小说作家 言情小说作家我比较喜欢匪我思存的,很虐,很悲,还有梅子黄时雨,笙离,叶萱,还有安宁的《温暖的玄》 小...
两个以名人的名字命名的风景名胜... 两个以名人的名字命名的风景名胜?快太白楼,李白。尚志公园,赵尚志。
幼儿教育的代表人物及其著作 幼儿教育的代表人物及其著作卡尔威特的《卡尔威特的教育》,小卡尔威特,他儿子成了天才后写的《小卡尔威特...
海贼王中为什么说路飞打凯多靠霸... 海贼王中为什么说路飞打凯多靠霸气升级?凯多是靠霸气升级吗?因为之前刚到时确实打不过人家因为路飞的实力...
运气不好拜财神有用吗运气不好拜... 运气不好拜财神有用吗运气不好拜财神有没有用1、运气不好拜财神有用。2、拜财神上香前先点蜡烛,照亮人神...