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

相关内容

热门资讯

自5月14日12时01分起我国... 转自:新华社新华社北京5月13日电 国务院关税税则委员会13日发布公告称,为落实中美经贸高层会谈的重...
宁德时代香港招股第2日已获12... 观点网讯:5月13日,市场消息显示,动力电池龙头宁德时代(03750.HK)香港IPO公开招股进入第...
欧股涨跌不一 德国DAX 30... 格隆汇5月13日|德国DAX 30指数涨0.23%,继续创收盘历史新高,法国股指涨0.20%,英国股...
综艺股份拟收购吉莱微延伸产业链... 转自:财联社财联社5月13日讯(记者 刘梦然)综艺股份(600770.SH)计划扩张其在半导体业务方...
派克新材去年净利下降46% ... 去年净利下滑的派克新材(605123),实控人计划减持。派克新材5月9日晚间公告,持有公司33.23...
掌趣科技高管刘惠城拟减持272... 5月13日,掌趣科技公告,董事长、总经理、非独立董事刘惠城计划在2025年6月5日至2025年9月4...
美平均关税税率仍为1934年来... 中美经贸高层会谈取得实质性进展,市场也给出了积极反应。不过,据美国媒体“消费者新闻与商业频道”报道,...
俄官员说将适时宣布与乌克兰谈判... 转自:新华社新华社莫斯科5月13日电(记者 黄河)俄罗斯总统新闻秘书佩斯科夫13日说,俄方正在为与乌...
日月明股东南昌国金公司拟减持8... 5月13日,日月明公告,股东南昌国金公司计划在2025年6月5日至2025年9月4日期间,通过竞价交...
西安市汉都第一学校开展防震减灾... 阳光讯(记者 梁永飞 通讯员 曹明明) 2025年5月12日是第17个全国防灾减灾日,主题为“人人讲...
河南一地新规:新增商品房现房销... 近日,河南信阳对商品房预售管理新政公开征求意见,其中提出“新出让土地开发的商品房,一律实行现房销售”...
中国—拉共体成员国重点领域合作... 2025年5月13日,中国—拉美和加勒比国家共同体(拉共体)论坛第四届部长级会议在北京举行。为深化论...
这地最新出手!新出让土地建商品... 近日,河南信阳对商品房预售管理新政公开征求意见,其中提出“新出让土地开发的商品房,一律实行现房销售”...
光云科技股东海南祺御企业管理合... 5月13日,光云科技公告,股东海南祺御企业管理合伙企业(有限合伙)计划在2025年6月5日至2025...
打虎!李春良落马 转自:扬子晚报5月13日,中央纪委国家监委网站发布消息,国家林业和草原局原党组成员、副局长李春良涉嫌...
凯美特气股东拟减持2086.0... 5月13日,凯美特气公告,股东湖南省财信常勤壹号基金合伙企业(有限合伙)、湖南省财信资产管理有限公司...
光弘科技高管李正大拟减持30.... 5月13日,光弘科技公告,副总经理李正大计划在2025年6月4日至2025年9月3日期间,通过竞价交...
中国平安股东大会回应分红、寿险... 界面新闻记者 | 曾令俊曾令俊 15月13日下午,中国平安(601318.SH、2318.HK)20...
中华银科技(00515)与爱能... 中华银科技(00515)发布公告,本集团一直积极寻求新业务机会,以拓展其业务,提升长期增长及股东价值...
Infinite Node F... 吴说获悉,非营利基金会 Infinite Node Foundation(NODE)宣布已从 Yug...