日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

两个sql交集_神奇的 SQL 之性能优化 → 让 SQL 飞起来

發(fā)布時(shí)間:2023/12/19 数据库 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 两个sql交集_神奇的 SQL 之性能优化 → 让 SQL 飞起来 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

寫(xiě)在前面

在像 Web 服務(wù)這樣需要快速響應(yīng)的應(yīng)用場(chǎng)景中,SQL 的性能直接決定了系統(tǒng)是否可以使用;特別在一些中小型應(yīng)用中,SQL 性能更是決定服務(wù)能否快速響應(yīng)的唯一標(biāo)準(zhǔn)

嚴(yán)格地優(yōu)化查詢(xún)性能時(shí),必須要了解所使用數(shù)據(jù)庫(kù)的功能特點(diǎn),此外,查詢(xún)速度慢并不只是因?yàn)?SQL 語(yǔ)句本身,還可能是因?yàn)閮?nèi)存分配不佳、文件結(jié)構(gòu)不合理、刷臟頁(yè)等其他原因

因此本文即將介紹的優(yōu)化 SQL 的方法不能解決所有的性能問(wèn)題,但是卻能處理很多因 SQL 寫(xiě)法不合理而產(chǎn)生的性能問(wèn)題

下文將盡量介紹一些不依賴(lài)具體數(shù)據(jù)庫(kù)實(shí)現(xiàn),使 SQL 執(zhí)行速度更快、消耗內(nèi)存更少的優(yōu)化技巧,只需調(diào)整 SQL 語(yǔ)句就能實(shí)現(xiàn)的通用的優(yōu)化Tip

環(huán)境準(zhǔn)備

下文所講的內(nèi)容是從 SQL 層面展開(kāi)的,而不是針對(duì)某種特性的數(shù)據(jù)庫(kù),也就是說(shuō),下文的內(nèi)容基本上適用于任何關(guān)系型數(shù)據(jù)庫(kù)

但是,關(guān)系型數(shù)據(jù)庫(kù)那么多,逐一來(lái)演示示例了,顯然不太現(xiàn)實(shí);我們以常用的 MySQL 來(lái)進(jìn)行示例的演示

MySQL 版本: 5.7.30-log ,存儲(chǔ)引擎: InnoDB

準(zhǔn)備兩張表: tbl_customer 和 tbl_recharge_record

使用高效的查詢(xún)

針對(duì)某一個(gè)查詢(xún),有時(shí)候會(huì)有多種 SQL 實(shí)現(xiàn),例如 IN、EXISTS、連接之間的互相轉(zhuǎn)換

從理論上來(lái)講,得到相同結(jié)果的不同 SQL 語(yǔ)句應(yīng)該有相同的性能,但遺憾的是,查詢(xún)優(yōu)化器生成的執(zhí)行計(jì)劃很大程度上要受到外部結(jié)構(gòu)的影響

因此,如果想優(yōu)化查詢(xún)性能,必須知道如何寫(xiě) SQL 語(yǔ)句才能使優(yōu)化器生成更高效的執(zhí)行計(jì)劃

使用 EXISTS 代替 IN

關(guān)于 IN,相信大家都比較熟悉,使用方便,也容易理解;雖說(shuō) IN 使用方便,但它卻存在性能瓶頸

如果 IN 的參數(shù)是 1,2,3 這樣的數(shù)值列表,一般還不需要特別注意,但如果參數(shù)是子查詢(xún),那么就需要注意了

在大多時(shí)候, [NOT] IN 和 [NOT] EXISTS 返回的結(jié)果是相同的,但是兩者用于子查詢(xún)時(shí),EXISTS 的速度會(huì)更快一些

假設(shè)我們要查詢(xún)有充值記錄的顧客信息,SQL 該怎么寫(xiě)?

相信大家第一時(shí)間想到的是 IN: SELECT * FROM tbl_customer WHERE ID IN (SELECT customer_id FROM tbl_recharge_record);

IN 使用起來(lái)確實(shí)簡(jiǎn)單,也非常好理解;我們來(lái)看下它的執(zhí)行計(jì)劃

我們?cè)賮?lái)看看 EXISTS 的執(zhí)行計(jì)劃:

可以看到,IN 的執(zhí)行計(jì)劃中新產(chǎn)生了一張臨時(shí)表: <subquery2> ,這會(huì)導(dǎo)致效率變慢

通常來(lái)講,EXISTS 比 IN 更快的原因有兩個(gè)

1、如果連接列(customer_id)上建立了索引,那么查詢(xún) tbl_recharge_record 時(shí)可以通過(guò)索引查詢(xún),而不是全表查詢(xún)

2、使用 EXISTS,一旦查到一行數(shù)據(jù)滿(mǎn)足條件就會(huì)終止查詢(xún),不用像使用 IN 時(shí)一樣進(jìn)行掃描全表(NOT EXISTS 也一樣)

當(dāng) IN 的參數(shù)是子查詢(xún)時(shí),數(shù)據(jù)庫(kù)首先會(huì)執(zhí)行子查詢(xún),然后將結(jié)果存儲(chǔ)在一張臨時(shí)表里(內(nèi)聯(lián)視圖),然后掃描整個(gè)視圖,很多情況下這種做法非常耗費(fèi)資源

使用 EXISTS 的話(huà),數(shù)據(jù)庫(kù)不會(huì)生成臨時(shí)表

但是從代碼的可讀性上來(lái)看,IN 要比 EXISTS 好,使用 IN 時(shí)的代碼看起來(lái)更加一目了然,易于理解

因此,如果確信使用 IN 也能快速獲取結(jié)果,就沒(méi)有必要非得改成 EXISTS 了

其實(shí)有很多數(shù)據(jù)庫(kù)也嘗試著改善了 IN 的性能

Oracle 數(shù)據(jù)庫(kù)中,如果我們?cè)谟兴饕牧猩鲜褂?IN, 也會(huì)先掃描索引

PostgreSQL 從版 本 7.4 起也改善了使用子查詢(xún)作為 IN 謂詞參數(shù)時(shí)的查詢(xún)速度

說(shuō)不定在未來(lái)的某一天,無(wú)論在哪個(gè)關(guān)系型數(shù)據(jù)庫(kù)上,IN 都能具備與 EXISTS 一樣的性能

關(guān)于 EXISTS,更多詳情可查看:神奇的 SQL 之謂詞 → 難理解的 EXISTS

使用連接代替 IN

其實(shí)在平時(shí)工作當(dāng)中,更多的是用連接代替 IN 來(lái)改善查詢(xún)性能,而非 EXISTS,不是說(shuō)連接更好,而是 EXISTS 很難掌握

回到問(wèn)題:查詢(xún)有充值記錄的顧客信息,如果用連接來(lái)實(shí)現(xiàn),SQL 改如何寫(xiě)?

這種寫(xiě)法能充分利用索引;而且,因?yàn)闆](méi)有了子查詢(xún),所以數(shù)據(jù)庫(kù)也不會(huì)生成中間表;所以,查詢(xún)效率是不錯(cuò)的

至于 JOIN 與 EXISTS 相比哪個(gè)性能更好,不太好說(shuō);如果沒(méi)有索引,可能 EXISTS 會(huì)略勝一籌,有索引的話(huà),兩者差不多

避免排序

說(shuō)到 SQL 的排序,我們第一時(shí)間想到的肯定是: ORDER BY ,通過(guò)它,我們可以按指定的某些列來(lái)順序輸出結(jié)果

但是,除了 ORDER BY 顯示的排序,數(shù)據(jù)庫(kù)內(nèi)部還有很多運(yùn)算在暗中進(jìn)行排序;會(huì)進(jìn)行排序的代表性的運(yùn)算有下面這些

如果只在內(nèi)存中進(jìn)行排序,那么還好;但是如果因內(nèi)存不足而需要在硬盤(pán)上排序,那么性能就會(huì)急劇下降

因此,盡量避免(或減少)無(wú)謂的排序,能夠大大提高查詢(xún)效率

靈活使用集合運(yùn)算符的 ALL 可選項(xiàng)

SQL 中有 UNION 、 INTERSECT 、 EXCEPT 三個(gè)集合運(yùn)算符,分表代表這集合運(yùn)算的 并集、交集、差集

默認(rèn)情況下,這些運(yùn)算符會(huì)為了排除掉重復(fù)數(shù)據(jù)而進(jìn)行排序

Using temporary 表示進(jìn)行了排序或分組,顯然這個(gè) SQL 沒(méi)有進(jìn)行分組,而是進(jìn)行了排序運(yùn)算

如果我們不在乎結(jié)果中是否有重復(fù)數(shù)據(jù),或者事先知道不會(huì)有重復(fù)數(shù)據(jù),可以使用 UNION ALL 代替 UNION

可以看到,執(zhí)行計(jì)劃中沒(méi)有排序運(yùn)算了

對(duì)于 INTERSECT 和 EXCEPT 也是一樣的,加上 ALL 可選項(xiàng)后就不會(huì)進(jìn)行排序了

加上 ALL 可選項(xiàng)是一個(gè)非常有效的優(yōu)化手段,但各個(gè)數(shù)據(jù)庫(kù)對(duì)它的實(shí)現(xiàn)情況卻是參差不齊,如下圖所示

注意:Oracle 使用 MINUS 代替 EXCEPT ;MySQL 壓根就沒(méi)有實(shí)現(xiàn) INTERSECT 和 EXCEPT 運(yùn)算

使用 EXISTS 代替 DISTINCT

為了排除重復(fù)數(shù)據(jù), DISTINCT 也會(huì)進(jìn)行排序

還記得用連接代替 IN 的案例嗎,如果不用 DISTINCT

SQL: SELECT tc.* FROM tbl_recharge_record trr LEFT JOIN tbl_customer tc on trr.customer_id = tc.id

那么查出來(lái)的結(jié)果會(huì)有很多重復(fù)記錄,我們改進(jìn) SQL

SELECT DISTINCT tc.* FROM tbl_recharge_record trr LEFT JOIN tbl_customer tc on trr.customer_id = tc.id

會(huì)發(fā)現(xiàn)執(zhí)行計(jì)劃中有個(gè) Using temporary ,表示用到了排序運(yùn)算

我們使用 EXISTS 來(lái)進(jìn)行優(yōu)化

可以看到,已經(jīng)規(guī)避了排序運(yùn)算

在極值函數(shù)中使用索引

SQL 語(yǔ)言里有兩個(gè)極值函數(shù): MAX 和 MIN ,使用這兩個(gè)函數(shù)時(shí)都會(huì)進(jìn)行排序

例如: SELECT MAX(recharge_amount) FROM tbl_recharge_record

會(huì)進(jìn)行全表掃描,并會(huì)進(jìn)行隱式的排序,找出單筆充值最大的金額

但是如果參數(shù)字段上建有索引,則只需要掃描索引,不需要掃描整張表

例如: SELECT MAX(customer_id) FROM tbl_recharge_record;

會(huì)通過(guò)索引: idx_c_id 進(jìn)行掃描,找出充值記錄中最大的顧客ID

這種方法并不是去掉了排序這一過(guò)程,而是優(yōu)化了排序前的查找速度,從而減弱排序?qū)φw性能的影響

能寫(xiě)在 WHERE 子句里的條件不要寫(xiě)在 HAVING 子句里

我們來(lái)看兩個(gè) SQL 以及其執(zhí)行結(jié)果

從結(jié)果上來(lái)看,兩條 SQL 一樣;但是從性能上來(lái)看,第二條語(yǔ)句寫(xiě)法效率更高,原因有兩個(gè)

減少排序的數(shù)據(jù)量

GROUP BY 子句聚合時(shí)會(huì)進(jìn)行排序,如果事先通過(guò) WHERE 子句篩選出一部分行,就能夠減輕排序的負(fù)擔(dān)

有效利用索引

WHERE 子句的條件里可以使用索引

HAVING 子句是針對(duì)聚合后生成的視圖進(jìn)行篩選的,但是很多時(shí)候聚合后的視圖都沒(méi)有繼承原表的索引結(jié)構(gòu)

關(guān)于 HAVING,更多詳情可查看:神奇的 SQL 之 HAVING → 容易被輕視的主角

在 GROUP BY 子句和 ORDER BY 子句中使用索引

一般來(lái)說(shuō),GROUP BY 子句和 ORDER BY 子句都會(huì)進(jìn)行排序

如果 GROUP BY 和 ORDER BY 的列有索引,那么可以提高查詢(xún)效率

特別是在一些數(shù)據(jù)庫(kù)中,如果列上建立的是唯一索引,那么排序過(guò)程本身都會(huì)被省略掉

使用索引

使用索引是最常用的 SQL 優(yōu)化手段,這個(gè)大家都知道,怕就怕大家不知道:明明有索引,為什么查詢(xún)還是這么慢(為什么索引沒(méi)用上)

關(guān)于索引未用到的情況,可查看:神奇的 SQL 之擦肩而過(guò) → 真的用到索引了嗎,本文就不做過(guò)多闡述了

總之就是:查詢(xún)盡量往索引上靠,規(guī)避索引未用上的情況

減少臨時(shí)表

在 SQL 中,子查詢(xún)的結(jié)果會(huì)被看成一張新表(臨時(shí)表),這張新表與原始表一樣,可以通過(guò) SQL 進(jìn)行操作

但是,頻繁使用臨時(shí)表會(huì)帶來(lái)兩個(gè)問(wèn)題

1、臨時(shí)表相當(dāng)于原表數(shù)據(jù)的一份備份,會(huì)耗費(fèi)內(nèi)存資源

2、很多時(shí)候(特別是聚合時(shí)),臨時(shí)表沒(méi)有繼承原表的索引結(jié)構(gòu)

因此,盡量減少臨時(shí)表的使用也是提升性能的一個(gè)重要方法

靈活使用 HAVING 子句

對(duì)聚合結(jié)果指定篩選條件時(shí),使用 HAVING 子句是基本原則

但是如果對(duì) HAVING 不熟,我們往往找出替代它的方式來(lái)實(shí)現(xiàn),就像這樣

然而,對(duì)聚合結(jié)果指定篩選條件時(shí)不需要專(zhuān)門(mén)生成中間表,像下面這樣使用 HAVING 子句就可以

HAVING 子句和聚合操作是同時(shí)執(zhí)行的,所以比起生成臨時(shí)表后再執(zhí)行 WHERE 子句,效率會(huì)更高一些,而且代碼看起來(lái)也更簡(jiǎn)潔

需要對(duì)多個(gè)字段使用 IN 謂詞時(shí),將它們匯總到一處

SQL-92 中加入了行與行比較的功能,這樣一來(lái),比較謂詞 = 、< 、> 和 IN 謂詞的參數(shù)就不再只是標(biāo)量值了,而應(yīng)是值列表了

我們來(lái)看一個(gè)示例,多個(gè)字段使用 IN 謂詞

這段代碼中用到了兩個(gè)子查詢(xún),我們可以進(jìn)行列匯總優(yōu)化,把邏輯寫(xiě)在一起

這樣一來(lái),子查詢(xún)不用考慮關(guān)聯(lián)性,而且只執(zhí)行一次就可以

還可以進(jìn)一步簡(jiǎn)化,在 IN 中寫(xiě)多個(gè)字段的組合

簡(jiǎn)化后,不用擔(dān)心連接字段時(shí)出現(xiàn)的類(lèi)型轉(zhuǎn)換問(wèn)題,也不會(huì)對(duì)字段進(jìn)行加工,因此可以使用索引

先進(jìn)行連接再進(jìn)行聚合

連接和聚合同時(shí)使用時(shí),先進(jìn)行連接操作可以避免產(chǎn)生中間表

合理地使用視圖

視圖是非常方便的工具,我們?cè)谌粘9ぷ髦薪?jīng)常使用

但是,如果沒(méi)有經(jīng)過(guò)深入思考就定義復(fù)雜的視圖,可能會(huì)帶來(lái)巨大的性能問(wèn)題

特別是視圖的定義語(yǔ)句中包含以下運(yùn)算的時(shí)候,SQL 會(huì)非常低效,執(zhí)行速度也會(huì)變得非常慢

總結(jié)

文中雖然列舉了幾個(gè)要點(diǎn),但其實(shí)優(yōu)化的核心思想只有一個(gè),那就是找出性能瓶頸所在,然后解決它

其實(shí)不只是數(shù)據(jù)庫(kù)和 SQL,計(jì)算機(jī)世界里容易成為性能瓶頸的也是對(duì)硬盤(pán),也就是文件系統(tǒng)的訪問(wèn)(因此可以通過(guò)增加內(nèi)存,或者使用訪問(wèn)速度更快的硬盤(pán)等方法來(lái)提升性能)

不管是減少排序還是使用索引,亦或是避免臨時(shí)表的使用,其本質(zhì)都是為了減少對(duì)硬盤(pán)的訪問(wèn)

小結(jié)下文中的 Tips

1、參數(shù)是子查詢(xún)時(shí),使用 EXISTS 或者 JOIN 代替 IN

2、在 SQL 中,很多運(yùn)算都會(huì)暗中進(jìn)行排序,盡量規(guī)避這些運(yùn)算

3、SQL 的書(shū)寫(xiě),盡量往索引上靠,避免用不上索引的情況

4、盡量減少使用中間表

總結(jié)

以上是生活随笔為你收集整理的两个sql交集_神奇的 SQL 之性能优化 → 让 SQL 飞起来的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲国产aⅴ精品一区二区 日韩黄色在线视频 | 国产一区二区三区在线 | 亚洲一区二区在线观看视频 | 黄色正能量网站 | 亚洲一区免费电影 | 国产孕交 | av在线高清观看 | 国产成人综合在线视频 | 成人av一区 | 91黄色免费 | heyzo在线播放 | 日本亚洲一区二区 | 天天操天天干视频 | 好色av| 亚洲成人日韩在线 | 亚洲欧美国产高清 | 国产l精品国产亚洲区久久 午夜青青草 | 国产人成| 天堂av最新网址 | 久久网免费视频 | 尤果网福利视频在线观看 | 久久激情片 | 女人高潮被爽到呻吟在线观看 | 女人十八毛片嫩草av | 一级欧美视频 | 手机av中文字幕 | 99视频精品| 91福利在线播放 | 福利视频一二区 | 欧洲精品视频在线 | av免费精品 | 欧美日韩一卡二卡 | 亚洲免费网址 | 69亚洲 | 麻豆乱码国产一区二区三区 | 色爽爽爽爽爽爽爽爽 | 麻豆福利在线观看 | 激情视频区 | 91麻豆国产在线观看 | 久久九九视频 | 免费欧美大片 | 色中色综合网 | 黄色一级带 | 中文字幕1| 亚洲一区二区三区在线免费观看 | 伊人久久精品视频 | 国产资源一区 | 成年人看的毛片 | 夜夜艹天天干 | 精品成人网 | 一级性生活免费视频 | 久久久www成人免费精品 | 国产com| 成人三级在线视频 | 91精品国产高潮对白 | 手机av免费看 | 日本少妇裸体 | 越南性xxxx精品hd | 91在线观看喷潮 | 日本aⅴ在线 | 久久黄色av | 欧美激情视频在线播放 | 欧美日韩乱 | 免费a网址 | 四虎一级片 | 一区二区免费在线播放 | 偷拍久久久 | 啪视频免费 | 嫩草视频在线观看 | 国产91啪 | 国产视频污在线观看 | 在线观看成人免费视频 | 久久午夜激情 | 黄色一级片黄色一级片 | 国产亚洲制服欧洲高清一区 | 国产一区二区三区www | 欧美专区日韩专区 | 天天爱综合网 | 污片免费看 | 亚洲vs天堂| 欧美人成在线 | 亚洲高清久久久 | 久久精品一区二区三 | 欧美黄色短视频 | 麻豆视频国产 | 欧美xxxx69| 俄罗斯美女一级爱片 | 国产精品麻豆入口 | 国产又爽又黄免费软件 | 日本高清中文字幕 | 草草在线视频 | 色屁屁在线 | 欧美性一区二区 | 精品无码人妻少妇久久久久久 | 欧美性猛交xxxx乱大交3 | 国产成人一区 | 午夜国产一区二区三区 | 国产精品视频一区二区三区, | 免费看污片的网站 |