爲何你們都說 SELECT * 效率低

1、效率低的緣由java

  1. 不須要的列會增長數據傳輸時間和網絡開銷
  2. 對於無用的大字段,如 varchar、blob、text,會增長 io 操做
  3. 失去MySQL優化器「覆蓋索引」策略優化的可能性
    2、索引知識延申
    聯合索引 (a,b,c)
    聯合索引的優點
    索引是建的越多越好嗎
    3、心得體會
    「面試官:「小陳,說一下你經常使用的SQL優化方式吧。」 陳小哈:「那不少啊,好比不要用SELECT ,查詢效率低。巴拉巴拉...」面試官:「爲何不要用SELECT ?它在哪些狀況下效率低呢?」 陳小哈:「SELECT * 它好像比寫指定列名多一次全表查詢吧,還多查了一些無用的字段。」面試官:「嗯...」 陳小哈:「emmm~ 沒了」陳小哈:「....??(幾個意思)」面試官:「嗯...好,那你還有什麼要問個人麼?」 陳小哈:「我問你個錘子,把老子簡歷還我!」

不管在工做仍是面試中,關於SQL中不要用「SELECT 」,都是你們聽爛了的問題,雖然說聽爛了,但廣泛理解仍是在很淺的層面,並無多少人去追根究底,探究其原理。
廢話很少說,本文帶你深刻了解一下"SELECT
"效率低的緣由及場景。
「本文很乾!請自備茶水,沒時間看記得先收藏 -- 來自一位被技術經理毒打多年的程序員的忠告
1、效率低的緣由mysql

先看一下最新《阿里java開發手冊(泰山版)》中 MySQL 部分描述:
4 - 1. 【強制】在表查詢中,一概不要使用 * 做爲查詢的字段列表,須要哪些字段必須明確寫明。說明:
增長查詢分析器解析成本。
增減字段容易與 resultMap 配置不一致。
無用字段增長網絡 消耗,尤爲是 text 類型的字段。
開發手冊中比較歸納的提到了幾點緣由,讓咱們深刻一些看看:程序員

  1. 不須要的列會增長數據傳輸時間和網絡開銷

用「SELECT 」數據庫須要解析更多的對象、字段、權限、屬性等相關內容,在 SQL 語句複雜,硬解析較多的狀況下,會對數據庫形成沉重的負擔。
增大網絡開銷;
有時會誤帶上如log、IconMD5之類的無用且大文本字段,數據傳輸size會幾何增漲。若是DB和應用程序不在同一臺機器,這種開銷很是明顯
即便 mysql 服務器和客戶端是在同一臺機器上,使用的協議仍是 tcp,通訊也是須要額外的時間。面試

  1. 對於無用的大字段,如 varchar、blob、text,會增長 io 操做

準確來講,長度超過 728 字節的時候,會先把超出的數據序列化到另一個地方,所以讀取這條記錄會增長一次 io 操做。(MySQL InnoDB)sql

  1. 失去MySQL優化器「覆蓋索引」策略優化的可能性

SELECT 杜絕了覆蓋索引的可能性,而基於MySQL優化器的「覆蓋索引」策略又是速度極快,效率極高,業界極爲推薦的查詢優化方式。
例如,有一個表爲t(a,b,c,d,e,f),其中,a爲主鍵,b列有索引。
那麼,在磁盤上有兩棵 B+ 樹,即彙集索引和輔助索引(包括單列索引、聯合索引),分別保存(a,b,c,d,e,f)和(a,b),若是查詢條件中where條件能夠經過b列的索引過濾掉一部分記錄,查詢就會先走輔助索引,若是用戶只須要a列和b列的數據,直接經過輔助索引就能夠知道用戶查詢的數據。
若是用戶使用select
,獲取了不須要的數據,則首先經過輔助索引過濾數據,而後再經過彙集索引獲取全部的列,這就多了一次b+樹查詢,速度必然會慢不少。數據庫

因爲輔助索引的數據比彙集索引少不少,不少狀況下,經過輔助索引進行覆蓋索引(經過索引就能獲取用戶須要的全部列),都不須要讀磁盤,直接從內存取,而彙集索引極可能數據在磁盤(外存)中(取決於buffer pool的大小和命中率),這種狀況下,一個是內存讀,一個是磁盤讀,速度差別就很顯著了,幾乎是數量級的差別。服務器

2、索引知識延申網絡

上面提到了輔助索引,在MySQL中輔助索引包括單列索引、聯合索引(多列聯合),單列索引就再也不贅述了,這裏提一下聯合索引的做用
聯合索引 (a,b,c)tcp

聯合索引 (a,b,c) 實際創建了 (a)、(a,b)、(a,b,c) 三個索引
咱們能夠將組合索引想成書的一級目錄、二級目錄、三級目錄,如index(a,b,c),至關於a是一級目錄,b是一級目錄下的二級目錄,c是二級目錄下的三級目錄。要使用某一目錄,必須先使用其上級目錄,一級目錄除外。
以下:ide

聯合索引的優點

1) 減小開銷

建一個聯合索引 (a,b,c) ,實際至關於建了 (a)、(a,b)、(a,b,c) 三個索引。每多一個索引,都會增長寫操做的開銷和磁盤空間的開銷。對於大量數據的表,使用聯合索引會大大的減小開銷!
2)覆蓋索引

對聯合索引 (a,b,c),若是有以下 sql 的,

SELECT a,b,c from table where a='xx' and b = 'xx';
那麼 MySQL 能夠直接經過遍歷索引取得數據,而無需回表,這減小了不少的隨機 io 操做。減小 io 操做,特別是隨機 io 實際上是 DBA 主要的優化策略。因此,在真正的實際應用中,覆蓋索引是主要的提高性能的優化手段之一。
3)效率高

索引列多,經過聯合索引篩選出的數據越少。好比有 1000W 條數據的表,有以下SQL:

select col1,col2,col3 from table where col1=1 and col2=2 and col3=3;
假設:假設每一個條件能夠篩選出 10% 的數據。
A. 若是隻有單列索引,那麼經過該索引能篩選出 1000W10%=100w 條數據,而後再回表從 100w 條數據中找到符合 col2=2 and col3= 3 的數據,而後再排序,再分頁,以此類推(遞歸);
B. 若是是(col1,col2,col3)聯合索引,經過三列索引篩選出 1000w10% 10% *10%=1w,效率提高可想而知!
索引是建的越多越好嗎

答案天然是否認的
數據量小的表不須要創建索引,創建會增長額外的索引開銷
不常常引用的列不要創建索引,由於不經常使用,即便創建了索引也沒有多大意義
常常頻繁更新的列不要創建索引,由於確定會影響插入或更新的效率
數據重複且分佈平均的字段,所以他創建索引就沒有太大的效果(例如性別字段,只有男女,不適合創建索引)
數據變動須要維護索引,意味着索引越多維護成本越高。
更多的索引也須要更多的存儲空間
3、心得體會

相信能看到這裏這老鐵要麼是對MySQL有着一腔熱血的,要麼就是喜歡滾鼠標的。來了就是緣分,若是從本文學到了東西,請不要吝嗇手中的贊哦,拒絕白嫖~有朋友問我,你對SQL規範那麼上心,平時你寫代碼不會用SELECT * 吧?咋可能啊,每天用。。代碼裏也在用(一臉羞愧),其實咱們的項目廣泛很小,數據量也上不去,性能上尚未遇到瓶頸,因此比較放縱。寫本篇文章主要是這個知識點網上總結的不多很散,也不規範,算是給本身也是給你們總結一份比較詳細的,值得記一下的。之後給面試官說完讓他無法找你茬

相關文章
相關標籤/搜索