1. 為什么大家都說SELECT * 效率低

        共 3055字,需瀏覽 7分鐘

         ·

        2020-11-09 00:45


        面試官:“小陳,說一下你常用的SQL優(yōu)化方式吧?!?/span>
        陳小哈:“那很多啊,比如不要用SELECT *,查詢效率低。巴拉巴拉...”

        面試官:“為什么不要用SELECT * ?它在哪些情況下效率低呢?”
        陳小哈:“SELECT * 它好像比寫指定列名多一次全表查詢吧,還多查了一些無用的字段?!?/span>

        面試官:“嗯...”
        陳小哈:“emmm~ 沒了”

        陳小哈:“....??(幾個意思)”

        面試官:“嗯...好,那你還有什么要問我的么?”
        陳小哈:“我問你個錘子,把老子簡歷還我!”

        無論在工作還是面試中,關于SQL中不要用“SELECT *”,都是大家聽爛了的問題,雖說聽爛了,但普遍理解還是在很淺的層面,并沒有多少人去追根究底,探究其原理。


        廢話不多說,本文帶你深入了解一下"SELECT * "效率低的原因及場景。

        本文很干!請自備茶水,沒時間看記得先收藏?-- 來自一位被技術經(jīng)理毒打多年的程序員的忠告

        一、效率低的原因

        先看一下最新《阿里java開發(fā)手冊(泰山版)》中 MySQL 部分描述:

        4 - 1.?【強制】在表查詢中,一律不要使用 * 作為查詢的字段列表,需要哪些字段必須明確寫明。?
        說明:

        • 增加查詢分析器解析成本。

        • 增減字段容易與 resultMap 配置不一致。

        • 無用字段增加網(wǎng)絡 消耗,尤其是 text 類型的字段。

        開發(fā)手冊中比較概括的提到了幾點原因,讓我們深入一些看看:

        1. 不需要的列會增加數(shù)據(jù)傳輸時間和網(wǎng)絡開銷

        1. 用“SELECT * ”數(shù)據(jù)庫需要解析更多的對象、字段、權限、屬性等相關內(nèi)容,在 SQL 語句復雜,硬解析較多的情況下,會對數(shù)據(jù)庫造成沉重的負擔。

        2. 增大網(wǎng)絡開銷;* 有時會誤帶上如log、IconMD5之類的無用且大文本字段,數(shù)據(jù)傳輸size會幾何增漲。如果DB和應用程序不在同一臺機器,這種開銷非常明顯

        3. 即使 mysql 服務器和客戶端是在同一臺機器上,使用的協(xié)議還是 tcp,通信也是需要額外的時間。

        2. 對于無用的大字段,如 varchar、blob、text,會增加 io 操作

        準確來說,長度超過 728 字節(jié)的時候,會先把超出的數(shù)據(jù)序列化到另外一個地方,因此讀取這條記錄會增加一次 io 操作。(MySQL InnoDB)


        3. 失去MySQL優(yōu)化器“覆蓋索引”策略優(yōu)化的可能性

        SELECT * 杜絕了覆蓋索引的可能性,而基于MySQL優(yōu)化器的“覆蓋索引”策略又是速度極快,效率極高,業(yè)界極為推薦的查詢優(yōu)化方式。

        例如,有一個表為t(a,b,c,d,e,f),其中,a為主鍵,b列有索引。

        那么,在磁盤上有兩棵 B+ 樹,即聚集索引和輔助索引(包括單列索引、聯(lián)合索引),分別保存(a,b,c,d,e,f)和(a,b),如果查詢條件中where條件可以通過b列的索引過濾掉一部分記錄,查詢就會先走輔助索引,如果用戶只需要a列和b列的數(shù)據(jù),直接通過輔助索引就可以知道用戶查詢的數(shù)據(jù)。

        如果用戶使用select *,獲取了不需要的數(shù)據(jù),則首先通過輔助索引過濾數(shù)據(jù),然后再通過聚集索引獲取所有的列,這就多了一次b+樹查詢,速度必然會慢很多。

        由于輔助索引的數(shù)據(jù)比聚集索引少很多,很多情況下,通過輔助索引進行覆蓋索引(通過索引就能獲取用戶需要的所有列),都不需要讀磁盤,直接從內(nèi)存取,而聚集索引很可能數(shù)據(jù)在磁盤(外存)中(取決于buffer pool的大小和命中率),這種情況下,一個是內(nèi)存讀,一個是磁盤讀,速度差異就很顯著了,幾乎是數(shù)量級的差異。

        二、索引知識延申

        上面提到了輔助索引,在MySQL中輔助索引包括單列索引、聯(lián)合索引(多列聯(lián)合),單列索引就不再贅述了,這里提一下聯(lián)合索引的作用

        聯(lián)合索引 (a,b,c)

        聯(lián)合索引 (a,b,c) 實際建立了 (a)、(a,b)、(a,b,c) 三個索引

        我們可以將組合索引想成書的一級目錄、二級目錄、三級目錄,如index(a,b,c),相當于a是一級目錄,b是一級目錄下的二級目錄,c是二級目錄下的三級目錄。要使用某一目錄,必須先使用其上級目錄,一級目錄除外。

        如下:

        ?聯(lián)合索引的優(yōu)勢

        1) 減少開銷

        建一個聯(lián)合索引 (a,b,c) ,實際相當于建了 (a)、(a,b)、(a,b,c) 三個索引。每多一個索引,都會增加寫操作的開銷和磁盤空間的開銷。對于大量數(shù)據(jù)的表,使用聯(lián)合索引會大大的減少開銷!

        2)覆蓋索引

        對聯(lián)合索引 (a,b,c),如果有如下 sql 的,


        SELECT a,b,c from table where a='xx' and b = 'xx';


        那么 MySQL 可以直接通過遍歷索引取得數(shù)據(jù),而無需回表,這減少了很多的隨機 io 操作。減少 io 操作,特別是隨機 io 其實是 DBA 主要的優(yōu)化策略。所以,在真正的實際應用中,覆蓋索引是主要的提升性能的優(yōu)化手段之一。


        3)效率高

        索引列多,通過聯(lián)合索引篩選出的數(shù)據(jù)越少。比如有 1000W 條數(shù)據(jù)的表,有如下SQL:


        select col1,col2,col3 from table where col1=1 and col2=2 and col3=3;


        假設:假設每個條件可以篩選出 10% 的數(shù)據(jù)。

        • A. 如果只有單列索引,那么通過該索引能篩選出 1000W10%=100w 條數(shù)據(jù),然后再回表從 100w 條數(shù)據(jù)中找到符合 col2=2 and col3= 3 的數(shù)據(jù),然后再排序,再分頁,以此類推(遞歸);

        • B. 如果是(col1,col2,col3)聯(lián)合索引,通過三列索引篩選出 1000w10% 10% *10%=1w,效率提升可想而知!

        索引是建的越多越好嗎

        ? ? ? ?答案自然是否定的

        • 數(shù)據(jù)量小的表不需要建立索引,建立會增加額外的索引開銷

        • 不經(jīng)常引用的列不要建立索引,因為不常用,即使建立了索引也沒有多大意義

        • 經(jīng)常頻繁更新的列不要建立索引,因為肯定會影響插入或更新的效率

        • 數(shù)據(jù)重復且分布平均的字段,因此他建立索引就沒有太大的效果(例如性別字段,只有男女,不適合建立索引)

        • 數(shù)據(jù)變更需要維護索引,意味著索引越多維護成本越高。

        • 更多的索引也需要更多的存儲空間

        三、心得體會

        相信能看到這里這老鐵要么是對MySQL有著一腔熱血的,要么就是喜歡滾鼠標的。來了就是緣分,如果從本文學到了東西,請不要吝嗇手中的贊哦。

        有朋友問我,你對SQL規(guī)范那么上心,平時你寫代碼不會用SELECT * 吧?


        咋可能啊,天天用。代碼里也在用(一臉羞愧),其實我們的項目普遍很小,數(shù)據(jù)量也上不去,性能上還沒有遇到瓶頸,所以比較放縱。


        寫本篇文章主要是這個知識點網(wǎng)上總結的很少很散,也不規(guī)范,算是給自己也是給大家總結一份比較詳細的,值得記一下的。以后給面試官說完讓他沒法找你茬


        順便吹波牛B,謝謝各位。

        來源:

        https://urlify.cn/ZvM3qe


        —??—

        回復關鍵字“簡明python ”,立即獲取入門必備書籍簡明python教程》電子版

        回復關鍵字爬蟲”,立即獲取爬蟲學習資料

        python入門與進階
        每天與你一起成長

        推薦閱讀


        點「在看」的人都變好看了哦!
        瀏覽 44
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
          
          

            1. 午夜国产福利一区二区刺激战场 | 性生生活大片又黄又 | 天天操天天操天天操 | 亚洲第一永久网站 | 国产BBBXXX |