精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

這么騷的SQL進階技巧,不怕被揍么?

運維 數據庫運維
由于工作需要,最近做了很多 BI 取數的工作,需要用到一些比較高級的 SQL 技巧,總結了一下工作中用到的一些比較騷的進階技巧,特此記錄一下,以方便自己查閱。

 由于工作需要,最近做了很多 BI 取數的工作,需要用到一些比較高級的 SQL 技巧,總結了一下工作中用到的一些比較騷的進階技巧,特此記錄一下,以方便自己查閱。

[[327588]]

 

圖片來自 Pexels

主要目錄如下:

  • SQL 的書寫規范
  • SQL 的一些進階使用技巧
  • SQL 的優化方法

SQL 的書寫規范

在介紹一些技巧之前,有必要強調一下規范,這一點我發現工作中經常被人忽略,其實遵循好的規范可讀性會好很多,應該遵循哪些規范呢?

①表名要有意義,且標準 SQL 中規定表名的第一個字符應該是字母。

②注釋,有單行注釋和多行注釋,如下:

  1. -- 單行注釋 
  2. -- 從SomeTable中查詢col_1  
  3. SELECT col_1 
  4.   FROM SomeTable; 
  5.  
  6. /* 
  7. 多行注釋 
  8. 從 SomeTable 中查詢 col_1  
  9. */ 
  10. SELECT col_1 
  11.   FROM SomeTable; 

多行注釋很多人不知道,這種寫法不僅可以用來添加真正的注釋,也可以用來注釋代碼,非常方便。

③縮進

就像寫 Java,Python 等編程語言一樣 ,SQL 也應該有縮進,良好的縮進對提升代碼的可讀性幫助很大。

以下分別是好的縮進與壞的縮進示例:

  1. -- 好的縮進 
  2. SELECT col_1,  
  3.     col_2,  
  4.     col_3, 
  5.     COUNT(*)  
  6.   FROM tbl_A 
  7.  WHERE col_1 = 'a' 
  8.    AND col_2 = ( SELECT MAX(col_2) 
  9.                    FROM tbl_B 
  10.                   WHERE col_3 = 100 ) 
  11.  GROUP BY col_1, 
  12.           col_2, 
  13.           col_3 
  14.  
  15.  
  16. -- 壞的示例 
  17. SELECT col1_1, col_2, col_3, COUNT(*) 
  18. FROM   tbl_A 
  19. WHERE  col1_1 = 'a' 
  20. AND    col1_2 = ( 
  21. SELECT MAX(col_2) 
  22. FROM   tbl_B 
  23. WHERE  col_3 = 100 
  24. GROUP BY col_1, col_2, col_3 

④空格

代碼中應該適當留有一些空格,如果一點不留,代碼都湊到一起, 邏輯單元不明確,閱讀的人也會產生額外的壓力。

以下分別是是好的與壞的示例:

  1. -- 好的示例 
  2. SELECT col_1 
  3.   FROM tbl_A A, tbl_B B 
  4.  WHERE ( A.col_1 >= 100 OR A.col_2 IN ( 'a''b' ) ) 
  5.    AND A.col_3 = B.col_3; 
  6.  
  7. -- 壞的示例 
  8. SELECT col_1 
  9.   FROM tbl_A A,tbl_B B 
  10.  WHERE (A.col_1>=100 OR A.col_2 IN ('a','b')) 
  11.    AND A.col_3=B.col_3; 

④大小寫

關鍵字使用大小寫,表名列名使用小寫,如下:

  1. SELECT col_1, col_2, col_3, 
  2.     COUNT(*) 
  3.   FROM tbl_A 
  4.  WHERE col_1 = 'a' 
  5.    AND col_2 = ( SELECT MAX(col_2) 
  6.                    FROM tbl_B 
  7.                   WHERE col_3 = 100 ) 
  8.  GROUP BY col_1, col_2, col_3 

花了這么多時間強調規范,有必要嗎,有!好的規范讓代碼的可讀性更好,更有利于團隊合作,之后的 SQL 示例都會遵循這些規范。

SQL 的一些進階使用技巧

①巧用 CASE WHEN 進行統計

來看看如何巧用 CASE WHEN 進行定制化統計,假設我們有如下的需求,希望根據左邊各個市的人口統計每個省的人口:

 

使用 CASE WHEN 如下:

  1. SELECT CASE pref_name 
  2.       WHEN '長沙' THEN '湖南'  
  3.       WHEN '衡陽' THEN '湖南' 
  4.       WHEN '海口' THEN '海南'  
  5.       WHEN '三亞' THEN '海南' 
  6.     ELSE '其他' END AS district, 
  7.     SUM(population)  
  8. FROM PopTbl 
  9. GROUP BY district; 

②巧用 CASE WHEN 進行更新

現在某公司員人工資信息表如下:

 

現在公司出臺了一個奇葩的規定:

  • 對當前工資為 1 萬以上的員工,降薪 10%。
  • 對當前工資低于 1 萬的員工,加薪 20%。

一些人不假思索可能寫出了以下的 SQL:

  1. --條件1 
  2. UPDATE Salaries 
  3. SET salary = salary * 0.9 WHERE salary >= 10000; 
  4. --條件2 
  5. UPDATE Salaries 
  6. SET salary = salary * 1.2 
  7. WHERE salary < 10000; 

這么做其實是有問題的, 什么問題,對小明來說,他的工資是 10500,執行第一個 SQL 后,工資變為 10500*0.9=9450, 緊接著又執行條件 2, 工資變為了 9450*1.2=11340,反而漲薪了!

如果用 CASE WHEN 可以解決此類問題,如下:

  1. UPDATE Salaries 
  2. SET salary = CASE WHEN salary >= 10000 THEN salary * 0.9 
  3. WHEN salary < 10000 THEN salary * 1.2 
  4. ELSE salary END

③巧用 HAVING 子句

一般 HAVING 是與 GROUP BY 結合使用的,但其實它是可以獨立使用的, 假設有如下表,第一列 seq 叫連續編號,但其實有些編號是缺失的,怎么知道編號是否缺失呢?

用 HAVING 表示如下:

  1. SELECT '存在缺失的編號' AS gap 
  2.   FROM SeqTbl 
  3. HAVING COUNT(*) <> MAX(seq); 

④自連接

針對相同的表進行的連接被稱為“自連接”(self join),這個技巧常常被人們忽視,其實是有挺多妙用的。

刪除重復行:上圖中有三個橘子,需要把這些重復的行給刪掉,用如下自連接可以解決:

  1. DELETE FROM Products P1 
  2.  WHERE id < ( SELECT MAX(P2.id)  
  3.                    FROM Products P2  
  4.                   WHERE P1.name = P2.name  
  5.                     AND P1.price = P2.price );  

排序:在 DB 中,我們經常需要按分數,人數,銷售額等進行排名,有 Oracle, DB2 中可以使用 RANK 函數進行排名,不過在 MySQL 中 RANK 函數未實現。

這種情況我們可以使用自連接來實現,如對以下 Products 表按價格高低進行排名:

使用自連接可以這么寫:

  1. -- 排序從 1 開始。如果已出現相同位次,則跳過之后的位次  
  2. SELECT P1.name
  3.        P1.price, 
  4.        (SELECT COUNT(P2.price) 
  5.           FROM Products P2 
  6.          WHERE P2.price > P1.price) + 1 AS rank_1 
  7.   FROM Products P1  
  8.   ORDER BY rank_1; 

結果如下:

  1. name price rank  
  2. ----- ------ ------  
  3. 橘子    100     1  
  4. 西瓜     80     2  
  5. 蘋果     50     3  
  6. 葡萄     50     3  
  7. 香蕉     50     3  
  8. 檸檬     30     6 

⑤巧用 COALESCE 函數

此函數作用返回參數中的第一個非空表達式,假設有如下商品,我們重新格式化一樣,如果 city 為 null,代表商品不在此城市發行。

但我們在展示結果的時候不想展示 null,而想展示 'N/A', 可以這么做:

  1. SELECT  
  2.     COALESCE(city, 'N/A'
  3.   FROM 
  4.     customers; 

 

SQL 性能優化技巧

①參數是子查詢時,使用 EXISTS 代替 IN

如果 IN 的參數是(1,2,3)這樣的值列表時,沒啥問題,但如果參數是子查詢時,就需要注意了。

比如,現在有如下兩個表:

 

現在我們要查出同時存在于兩個表的員工,即田中和鈴木,則以下用 IN 和 EXISTS 返回的結果是一樣,但是用 EXISTS 的 SQL 會更快:

  1. -- 慢 
  2. SELECT *  
  3.   FROM Class_A 
  4. WHERE id IN (SELECT id  
  5.                FROM  CLASS_B); 
  6.  
  7. -- 快 
  8. SELECT * 
  9.   FROM Class_A A  
  10.  WHERE EXISTS 
  11. (SELECT *  
  12.    FROM Class_B  B 
  13.   WHERE A.id = B.id); 

為啥使用 EXISTS 的 SQL 運行更快呢,有兩個原因:

  • 可以`用到索引,如果連接列 (id) 上建立了索引,那么查詢 Class_B 時不用查實際的表,只需查索引就可以了。
  • 如果使用 EXISTS,那么只要查到一行數據滿足條件就會終止查詢, 不用像使用 IN 時一樣掃描全表。在這一點上 NOT EXISTS 也一樣。

另外如果 IN 后面如果跟著的是子查詢,由于 SQL 會先執行 IN 后面的子查詢,會將子查詢的結果保存在一張臨時的工作表里(內聯視圖),然后掃描整個視圖。

顯然掃描整個視圖這個工作很多時候是非常耗時的,而用 EXISTS 不會生成臨時表。

當然了,如果 IN 的參數是子查詢時,也可以用連接來代替,如下:

  1. -- 使用連接代替 IN SELECT A.id, A.name 
  2. FROM Class_A A INNER JOIN Class_B B ON A.id = B.id; 

用到了 「id」列上的索引,而且由于沒有子查詢,也不會生成臨時表。

②避免排序

SQL 是聲明式語言,即對用戶來說,只關心它能做什么,不用關心它怎么做,這樣可能會產生潛在的性能問題:排序。

會產生排序的代表性運算有下面這些:

  • GROUP BY 子句
  • ORDER BY 子句
  • 聚合函數(SUM、COUNT、AVG、MAX、MIN)
  • DISTINCT
  • 集合運算符(UNION、INTERSECT、EXCEPT)
  • 窗口函數(RANK、ROW_NUMBER 等)

如果在內存中排序還好,但如果內存不夠導致需要在硬盤上排序上的話,性能就會急劇下降,所以我們需要減少不必要的排序。

怎樣做可以減少排序呢?有如下幾點:

使用集合運算符的 ALL 可選項:SQL 中有 UNION,INTERSECT,EXCEPT 三個集合運算符。

默認情況下,這些運算符會為了避免重復數據而進行排序,對比一下使用 UNION 運算符加和不加 ALL 的情況:

 

注意:加 ALL 是優化性能非常有效的手段,不過前提是不在乎結果是否有重復數據。

使用 EXISTS 代表 DISTINCT:為了排除重復數據,DISTINCT 也會對結果進行排序,如果需要對兩張表的連接結果進行去重,可以考慮用 EXISTS 代替 DISTINCT,這樣可以避免排序。

如何找出有銷售記錄的商品,使用如下 DISTINCT 可以:

  1. SELECT DISTINCT I.item_no 
  2. FROM Items I INNER JOIN SalesHistory SH 
  3. ON I. item_no = SH. item_no; 

不過更好的方式是使用 EXISTS:

  1. SELECT item_no FROM Items I 
  2. WHERE EXISTS  
  3.         (SELECT * 
  4.            FROM SalesHistory SH 
  5.           WHERE I.item_no = SH.item_no); 

既用到了索引,又避免了排序對性能的損耗。

②在極值函數中使用索引(MAX/MIN)

使用 MAX/ MIN 都會對進行排序,如果參數字段上沒加索引會導致全表掃描,如果建有索引,則只需要掃描索引即可,對比如下:

  1. -- 這樣寫需要掃描全表  
  2. SELECT MAX(item) 
  3.   FROM Items; 
  4.  
  5. -- 這樣寫能用到索引  
  6. SELECT MAX(item_no) 
  7.   FROM Items; 

注意:極值函數參數推薦為索引列中并不是不需要排序,而是優化了排序前的查找速度(畢竟索引本身就是有序排列的)。

③能寫在 WHERE 子句里的條件不要寫在 HAVING 子句里

下列 SQL 語句返回的結果是一樣的:

  1. -- 聚合后使用 HAVING 子句過濾 
  2. SELECT sale_date, SUM(quantity) 
  3.   FROM SalesHistory GROUP BY sale_date 
  4. HAVING sale_date = '2007-10-01'
  5.  
  6. -- 聚合前使用 WHERE 子句過濾 
  7. SELECT sale_date, SUM(quantity) 
  8.   FROM SalesHistory 
  9.  WHERE sale_date = '2007-10-01'  
  10.  GROUP BY sale_date; 

使用第二條語句效率更高,原因主要有兩點:

  • 使用 GROUP BY 子句進行聚合時會進行排序,如果事先通過 WHERE 子句能篩選出一部分行,能減輕排序的負擔。
  • 在 WHERE 子句中可以使用索引,而 HAVING 子句是針對聚合后生成的視頻進行篩選的,但很多時候聚合后生成的視圖并沒有保留原表的索引結構。

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

GROUP BY 子句和 ORDER BY 子句一般都會進行排序,以對行進行排列和替換,不過如果指定帶有索引的列作為這兩者的參數列,由于用到了索引,可以實現高速查詢,由于索引是有序的,排序本身都會被省略掉

⑤使用索引時,條件表達式的左側應該是原始字段

假設我們在 col 列上建立了索引,則下面這些 SQL 語句無法用到索引:

  1. SELECT * 
  2.   FROM SomeTable 
  3.  WHERE col * 1.1 > 100; 
  4.  
  5. SELECT * 
  6.   FROM SomeTable 
  7.  WHERE SUBSTR(col, 1, 1) = 'a'

以上第一個 SQL 在索引列上進行了運算, 第二個 SQL 對索引列使用了函數,均無法用到索引,正確方式是把列單獨放在左側,如下:

  1. SELECT * 
  2.   FROM SomeTable 
  3.  WHERE col_1 > 100 / 1.1; 

當然如果需要對此列使用函數,則無法避免在左側運算,可以考慮使用函數索引,不過一般不推薦隨意這么做。

⑥盡量避免使用否定形式

如下的幾種否定形式不能用到索引:

 

  • <>
  • !=
  • NOT IN

所以以下 了SQL 語句會導致全表掃描:

  1. SELECT * 
  2.   FROM SomeTable 
  3.  WHERE col_1 <> 100; 

可以改成以下形式:

  1. SELECT * 
  2.   FROM SomeTable 
  3.  WHERE col_1 > 100 or col_1 < 100; 

⑦進行默認的類型轉換

假設 col 是 char 類型,則推薦使用以下第二,三條 SQL 的寫法,不推薦第一條 SQL 的寫法:

  1. × SELECT * FROM SomeTable WHERE col_1 = 10; 
  2. ○ SELECT * FROM SomeTable WHERE col_1 = '10'
  3. ○ SELECT * FROM SomeTable WHERE col_1 = CAST(10, AS CHAR(2)); 

雖然第一條 SQL 會默認把 10 轉成 '10',但這種默認類型轉換不僅會增加額外的性能開銷,還會導致索引不可用,所以建議使用的時候進行類型轉換。

⑧減少中間表

在 SQL 中,子查詢的結果會產生一張新表,不過如果不加限制大量使用中間表的話,會帶來兩個問題:一是展示數據需要消耗內存資源,二是原始表中的索引不容易用到,所以盡量減少中間表也可以提升性能。

⑨靈活使用 HAVING 子句

這一點與上面第八條相呼應,對聚合結果指定篩選條件時,使用 HAVING 是基本的原則,可能一些工程師會傾向于使用下面這樣的寫法:

  1. SELECT * 
  2.   FROM (SELECT sale_date, MAX(quantity) AS max_qty 
  3.           FROM SalesHistory  
  4.          GROUP BY sale_date) TMP 
  5.          WHERE max_qty >= 10; 

雖然上面這樣的寫法能達到目的,但會生成 TMP 這張臨時表,所以應該使用下面這樣的寫法:

  1. SELECT sale_date, MAX(quantity)  
  2.   FROM SalesHistory 
  3.  GROUP BY sale_date 
  4. HAVING MAX(quantity) >= 10; 

HAVING 子句和聚合操作是同時執行的,所以比起生成中間表后再執行 HAVING 子句,效率會更高,代碼也更簡潔。

⑩需要對多個字段使用 IN 謂詞時,將它們匯總到一處

一個表的多個字段可能都使用了 IN 謂詞,如下:

  1. SELECT id, state, city  
  2.   FROM Addresses1 A1 
  3.  WHERE state IN (SELECT state 
  4.                    FROM Addresses2 A2 
  5.                   WHERE A1.id = A2.id)  
  6.     AND city IN (SELECT city 
  7.                    FROM Addresses2 A2  
  8.                   WHERE A1.id = A2.id); 

這段代碼用到了兩個子查詢,也就產生了兩個中間表,可以像下面這樣寫:

  1. SELECT * 
  2.   FROM Addresses1 A1 
  3.  WHERE id || state || city 
  4.  IN (SELECT id || state|| city 
  5.        FROM Addresses2 A2); 

這樣子查詢不用考慮關聯性,沒有中間表產生,而且只執行一次即可。

⑪使用延遲查詢優化 limit [offset],[rows]

經常出現類似以下的 SQL 語句:

  1. SELECT * FROM film LIMIT 100000, 10 

Offset 特別大!這是我司出現很多慢 SQL 的主要原因之一,尤其是在跑任務需要分頁執行時,經常跑著跑著 Offset 就跑到幾十萬了,導致任務越跑越慢。

LIMIT 能很好地解決分頁問題,但如果 Offset 過大的話,會造成嚴重的性能問題。

原因主要是因為 MySQL 每次會把一整行都掃描出來,掃描 Offset 遍,找到 Offset 之后會拋棄 Offset 之前的數據,再從 Offset 開始讀取 10 條數據,顯然,這樣的讀取方式問題。

可以通過延遲查詢的方式來優化,假設有以下 SQL,有組合索引(sex,rating):

  1. SELECT <cols> FROM profiles where sex='M' order by rating limit 100000, 10; 

則上述寫法可以改成如下寫法:

  1. SELECT <cols>  
  2.   FROM profiles  
  3. inner join 
  4. (SELECT id form FROM profiles where x.sex='M' order by rating limit 100000, 10) 
  5. as x using(id); 

這里利用了覆蓋索引的特性,先從覆蓋索引中獲取 100010 個 id,再丟充掉前 100000 條 id,保留最后 10 個 id 即可,丟掉 100000 條 id 不是什么大的開銷,所以這樣可以顯著提升性能。

⑫利用 LIMIT 1 取得唯一行

數據庫引擎只要發現滿足條件的一行數據則立即停止掃描,,這種情況適用于只需查找一條滿足條件的數據的情況。

⑬注意組合索引,要符合最左匹配原則才能生效

假設存在這樣順序的一個聯合索引“col_1, col_2, col_3”。這時,指定條件的順序就很重要。

  1. ○ SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 AND col_3 = 500; 
  2. ○ SELECT * FROM SomeTable WHERE col_1 = 10 AND col_2 = 100 ; 
  3. × SELECT * FROM SomeTable WHERE col_2 = 100 AND col_3 = 500 ; 

前面兩條會命中索引,第三條由于沒有先匹配 col_1,導致無法命中索引, 另外如果無法保證查詢條件里列的順序與索引一致,可以考慮將聯合索引 拆分為多個索引。

⑭使用 LIKE 謂詞時,只有前方一致的匹配才能用到索引(最左匹配原則)

  1. × SELECT * FROM SomeTable WHERE col_1 LIKE '%a'
  2. × SELECT * FROM SomeTable WHERE col_1 LIKE '%a%'
  3. ○ SELECT * FROM SomeTable WHERE col_1 LIKE 'a%'

上例中,只有第三條會命中索引,前面兩條進行后方一致或中間一致的匹配無法命中索引。

⑮簡單字符串表達式

模型字符串可以使用 _ 時,盡可能避免使用 %,假設某一列上為 char(5)。

不推薦:

  1. SELECT  
  2.     first_name,  
  3.     last_name, 
  4.     homeroom_nbr 
  5.   FROM Students 
  6.  WHERE homeroom_nbr LIKE 'A-1%'

推薦:

  1. SELECT first_name, last_name 
  2. homeroom_nbr 
  3.   FROM Students 
  4.  WHERE homeroom_nbr LIKE 'A-1__'--模式字符串中包含了兩個下劃線 

⑯盡量使用自增 id 作為主鍵

比如現在有一個用戶表,有人說身份證是唯一的,也可以用作主鍵,理論上確實可以,不過用身份證作主鍵的話,一是占用空間相對于自增主鍵大了很多,二是很容易引起頻繁的頁分裂,造成性能問題。

主鍵選擇的幾個原則:自增,盡量小,不要對主鍵進行修改。

⑰如何優化 count(*)

使用以下 SQL 會導致慢查詢:

  1. SELECT COUNT(*) FROM SomeTable 
  2. SELECT COUNT(1) FROM SomeTable 

原因是會造成全表掃描,有人說 COUNT(*) 不是會利用主鍵索引去查找嗎,怎么還會慢,這就要談到 MySQL 中的聚簇索引和非聚簇索引了。

聚簇索引葉子節點上存有主鍵值+整行數據,非聚簇索葉子節點上則存有輔助索引的列值+主鍵值,如下:

 

所以就算對 COUNT(*) 使用主鍵查找,由于每次取出主鍵索引的葉子節點時,取的是一整行的數據,效率必然不高。

但是非聚簇索引葉子節點只存儲了「列值+主鍵值」,這也啟發我們可以用非聚簇索引來優化,假設表有一列叫 status,為其加上索引后,可以用以下語句優化:

  1. SELECT COUNT(status) FROM SomeTable 

有人曾經測過(見文末參考鏈接),假設有 100 萬行數據,使用聚簇索引來查找行數的,比使用 COUNT(*) 查找速度快 10 幾倍。不過需要注意的是通過這種方式無法計算出 status 值為 null 的那些行。

如果主鍵是連續的,可以利用 MAX(id) 來查找,MAX 也利用到了索引,只需要定位到最大 id 即可,性能極好,如下,秒現結果:

  1. SELECT MAX(id) FROM SomeTable 

說句題句話,有人說用 MyISAM 引擎調用 COUNT(*) 非常快,那是因為它提前把行數存在磁盤中了,直接拿,當然很快,不過如果有 WHERE 的限制。

⑱避免使用 SELECT *,盡量利用覆蓋索引來優化性能

SELECT * 會提取出一整行的數據,如果查詢條件中用的是組合索引進行查找,還會導致回表(先根據組合索引找到葉子節點,再根據葉子節點上的主鍵回表查詢一整行),降低性能。

而如果我們所要的數據就在組合索引里,只需讀取組合索引列,這樣網絡帶寬將大大減少,假設有組合索引列 (col_1, col_2)。

推薦用:

  1. SELECT col_1, col_2  
  2.   FROM SomeTable  
  3.  WHERE col_1 = xxx AND col_2 = xxx 

不推薦用:

  1. SELECT * 
  2.   FROM SomeTable  
  3.  WHERE col_1 = xxx AND  col_2 = xxx 

⑲如有必要,使用 force index() 強制走某個索引

業務團隊曾經出現類似以下的慢 SQL 查詢:

  1. SELECT * 
  2.   FROM  SomeTable 
  3.  WHERE `status` = 0 
  4.    AND `gmt_create` > 1490025600 
  5.    AND `gmt_create` < 1490630400 
  6.    AND `id` > 0 
  7.    AND `post_id` IN ('67778''67811''67833''67834''67839''67852''67861''67868''67870''67878''67909''67948''67951''67963''67977''67983''67985''67991''68032''68038'/*... omitted 480 items ...*/) 
  8. order by id asc limit 200; 

post_id 也加了索引,理論上走 post_id 索引會很快查詢出來,但實現了通過 EXPLAIN 發現走的卻是 id 的索引(這里隱含了一個常見考點,在多個索引的情況下, MySQL 會如何選擇索引)。

而 id > 0 這個查詢條件沒啥用,直接導致了全表掃描, 所以在有多個索引的情況下一定要慎用。

可以使用 force index 來強制走某個索引,以這個例子為例,可以強制走 post_id 索引,效果立桿見影。

這種由于表中有多個索引導致 MySQL 誤選索引造成慢查詢的情況在業務中也是非常常見。

一方面是表索引太多,另一方面也是由于 SQL 語句本身太過復雜導致, 針對本例這種復雜的 SQL 查詢,其實用 ElasticSearch 搜索引擎來查找更合適,有機會到時出一篇文章說說。

⑳使用 EXPLAIN 來查看 SQL 執行計劃

上個點說了,可以使用 EXPLAIN 來分析 SQL 的執行情況,如怎么發現上文中的最左匹配原則不生效呢,執行 「EXPLAIN+SQL 語句」可以發現 key 為 None,說明確實沒有命中索引:

 

我司在提供 SQL 查詢的同時,也貼心地加了一個 EXPLAIN 功能及 SQL 的優化建議,建議各大公司效仿,如圖示:

 

  • 批量插入,速度更快

當需要插入數據時,批量插入比逐條插入性能更高。

推薦用:

  1. -- 批量插入 
  2. INSERT INTO TABLE (id, user_id, title) VALUES (1, 2, 'a'),(2,3,'b'); 

不推薦用:

  1. INSERT INTO TABLE (id, user_id, title) VALUES (1, 2, 'a'); 
  2. INSERT INTO TABLE (id, user_id, title) VALUES (2,3,'b'); 

批量插入 SQL 執行效率高的主要原因是合并后日志量 MySQL 的 binlog 和 innodb 的事務讓日志減少了,降低日志刷盤的數據量和頻率,從而提高了效率。

  • 慢日志 SQL 定位

前面我們多次說了 SQL 的慢查詢,那么該怎么定位這些慢查詢 SQL 呢,主要用到了以下幾個參數:

 

這幾個參數一定要配好,再根據每條慢查詢對癥下藥,像我司每天都會把這些慢查詢提取出來通過郵件給形式發送給各個業務團隊,以幫忙定位解決。

小結:業務生產中可能還有很多 CASE 導致了慢查詢,其實細細品一下,都會發現這些都和 MySQL 索引的底層數據 B+ 樹有莫大的關系。

總結

本文一開始花了挺大的篇幅來講解 SQL 的規范,請大家務必重視這部分內部,良好的規范有利于團隊協作,對于代碼的閱讀也比較友好。

之后介紹了一些 SQL 的比較高級的用法,巧用這些技巧確實能達到事半功倍的效果。

 

 

責任編輯:武曉燕 來源: 碼海
相關推薦

2020-09-18 11:20:28

Python文件代碼

2014-08-26 11:03:54

2023-08-06 12:50:19

機器人AI

2020-07-07 07:30:58

Vue策略模式

2018-07-02 14:12:26

Python爬蟲反爬技術

2019-06-03 10:07:20

Java開發代碼

2020-07-07 14:35:41

Python數據分析命令

2011-08-10 09:30:14

云計算

2010-07-13 15:49:40

SQL Server排

2020-06-03 09:14:41

文件代碼Linux

2021-03-02 09:56:33

技術研發指標

2022-09-27 10:52:25

Pythonprint函數

2024-10-09 12:18:38

2011-09-15 16:48:09

2022-11-02 19:08:48

微服務輪詢消費者

2018-09-30 15:30:44

CPU漲價主機

2020-05-17 16:19:59

JavaScript代碼開發

2011-08-26 13:09:25

2020-09-18 18:08:12

測試接口技巧

2022-03-16 12:06:25

軟件禁止技術
點贊
收藏

51CTO技術棧公眾號

一区二区三区视频免费| 亚洲综合成人在线| 91日韩在线播放| 亚洲成人生活片| 第一区第二区在线| 色八戒一区二区三区| 大桥未久一区二区三区| 亚洲av毛片成人精品| 毛片av一区二区三区| 久久久噜噜噜久久中文字免| 美女爆乳18禁www久久久久久| 天堂综合在线播放| 精品露脸国产偷人在视频| 亚洲午夜精品久久| 污污网站在线免费观看| 久久99久久久欧美国产| 午夜精品一区二区三区在线| 国产成人免费在线观看视频| 青青一区二区| 麻豆国产精品777777在线| 盗摄精品av一区二区三区| 69视频在线播放| 国产suv精品一区二区68| 欧美调教在线| 日韩精品一区二区三区swag| 中文字幕国内自拍| 国产精品一二三产区| 国产精品久久久99| 欧洲视频一区二区三区| 风流少妇一区二区三区91| 毛片不卡一区二区| 国产精品69精品一区二区三区| 久久久精品国产sm调教| 欧美岛国激情| 国产午夜精品一区理论片飘花| 熟妇高潮一区二区| 久久综合给合| 91精品国产麻豆| 日日噜噜夜夜狠狠| 高清成人在线| 欧美性xxxx| 波多野结衣综合网| 青春草在线视频| 亚洲精品日产精品乱码不卡| 影音先锋欧美资源| 91精品专区| 国产女同互慰高潮91漫画| 精品在线观看一区二区| 女人18毛片一区二区三区| 国产精品中文字幕欧美| 国产一区二区在线免费视频| 一级黄色a毛片| 免费亚洲电影在线| 国产在线观看精品一区二区三区| 中文字幕免费观看视频| 日本欧美一区二区三区| 国产精品免费福利| 中文字幕永久免费视频| 久久精品理论片| 国产日韩在线亚洲字幕中文| 伊人网免费视频| 麻豆91在线播放免费| 国产精品一区二区久久久| 亚洲av人无码激艳猛片服务器| 日本成人中文字幕在线视频| 国产精品欧美日韩久久| 国产一区二区三区成人| 国产综合色在线视频区| 51蜜桃传媒精品一区二区| 99久久精品国产一区二区成人| 国产乱码精品一区二区三区忘忧草| 91色琪琪电影亚洲精品久久| 亚洲成人77777| 91网站最新网址| 日韩欧美第二区在线观看| 日本韩国精品一区二区| 国产亚洲欧美日韩俺去了| 亚洲欧洲一二三| 免费a在线看| 亚洲一区二区三区影院| 亚洲国产精品久久久久婷蜜芽| 97久久香蕉国产线看观看| 欧美在线不卡视频| 真实乱偷全部视频| 香蕉久久99| 日韩中文视频免费在线观看| 欧美成人精品欧美一级私黄| www.午夜激情| 国产一区视频在线观看免费| 午夜精品久久久久久久男人的天堂 | 成人动漫在线一区| 欧美一区视久久| 成人在线播放| 欧美日韩国产在线播放| 九九热免费精品视频| 久久久久久久久久久久电影| 精品亚洲国产成av人片传媒| 91久久久久久久久久久久久久| 精品动漫3d一区二区三区免费版| 国产精品91免费在线| www.久久久久久| 国产色91在线| 国产一区二区三区乱码| 成人精品动漫| 亚洲精品大尺度| 国产福利视频网站| 男人的天堂亚洲| 2022国产精品| 婷婷激情在线| 色88888久久久久久影院按摩| 中国老熟女重囗味hdxx| 成人久久一区| 欧美一级成年大片在线观看| 精品国产乱码一区二区三| 久久久精品一品道一区| 国产系列第一页| 性感美女一区二区在线观看| 精品国产免费一区二区三区香蕉| 制服丨自拍丨欧美丨动漫丨| 另类激情亚洲| 国产一区二区三区四区五区在线| v片在线观看| 欧美日韩三级在线| 中日韩精品一区二区三区| 国内久久视频| 亚洲伊人久久综合| 免费黄色在线| 欧美视频在线一区| 右手影院亚洲欧美| 日韩视频久久| 国产偷久久久精品专区| 在线h片观看| 91精品啪在线观看国产60岁| 手机免费观看av| 日韩专区在线视频| 欧美成人免费在线| 无码小电影在线观看网站免费| 精品少妇一区二区三区视频免付费| 国产探花视频在线播放| 天堂久久久久va久久久久| 久久精品五月婷婷| 波多野一区二区| 亚洲爱爱爱爱爱| 久久9999久久免费精品国产| 国产高清无密码一区二区三区| 韩国黄色一级大片| 国产电影一区二区| 欧美美女18p| 精品国产18久久久久久| 依依成人精品视频| 国产麻豆剧传媒精品国产| 狠狠入ady亚洲精品| 国产精品入口免费| 国产传媒在线观看| 亚洲精品视频在线播放| 久久精品视频5| 国产欧美精品一区aⅴ影院| 少妇黄色一级片| 日韩国产欧美一区二区| 91精品国产综合久久香蕉| 免费日本一区二区三区视频| 日韩一二三区视频| 免费在线视频观看| 9久草视频在线视频精品| 亚洲中文字幕无码中文字| 国产不卡一区| 亚洲精品乱码久久久久久| 国产日韩在线一区| 九七电影韩国女主播在线观看| 777午夜精品免费视频| 一级黄色录像视频| 北岛玲一区二区三区四区| 免费看的黄色大片| 成人在线免费观看91| 亚洲精品日韩激情在线电影| 免费污视频在线| 日韩精品免费在线| 中文字幕一区2区3区| 亚洲男帅同性gay1069| 亚洲久久久久久| 日本v片在线高清不卡在线观看| 亚洲综合激情五月| 九色丨蝌蚪丨成人| 国产美女直播视频一区| 国产偷倩在线播放| 亚洲天堂精品在线| 国产高清在线免费| 欧美午夜片欧美片在线观看| 精品国产国产综合精品| www.性欧美| 欧美三级理论片| 影音先锋在线一区| 无遮挡亚洲一区| 成人搞黄视频| 国产精品丝袜高跟| 51精品在线| www.久久色.com| 天天操天天干天天爱| 欧美日韩一区高清| 人人干人人干人人干| 亚洲欧美综合另类在线卡通| 九色综合日本| 九九视频免费在线观看| 成人自拍视频在线| 亚洲免费看av| 另类亚洲自拍| 国产色一区二区三区| 91一区二区| 欧美日韩亚洲免费| theporn国产在线精品| 91精品国产综合久久久久久久久| 午夜影院在线播放| 欧美高跟鞋交xxxxhd| 午夜免费福利在线观看| 亚洲女人被黑人巨大进入al | 精品美女在线播放| 伊人成人在线观看| 色悠悠亚洲一区二区| 国产一级av毛片| 亚洲欧美日韩久久| 99热6这里只有精品| 久久亚洲一级片| 亚洲香蕉中文网| 国产高清久久久| 91看片破解版| 久久99热狠狠色一区二区| 激情内射人妻1区2区3区| 中日韩男男gay无套| 国产曰肥老太婆无遮挡| 女主播福利一区| 强开小嫩苞一区二区三区网站 | 91精品国产毛片武则天| 97精品国产一区二区三区 | jizz在线观看视频| 亚洲欧洲视频在线| 日本又骚又刺激的视频在线观看| 亚洲成av人影院在线观看 | 亚洲欧美综合精品久久成人| 午夜福利理论片在线观看| 精品国产乱码久久久久久夜甘婷婷| 91福利免费视频| 7777精品伊人久久久大香线蕉的| 又骚又黄的视频| 欧美色男人天堂| 国产精品sm调教免费专区| 色婷婷一区二区| 亚洲无码精品一区二区三区| 在线免费不卡视频| 中日精品一色哟哟| 欧美日本一道本| 国产精品一区二区三区在线免费观看 | 一区二区三区视频免费观看| 久久久久久久有限公司| 欧美极品在线观看| 色狠狠久久av五月综合| 日韩一区二区三区免费播放| 一级做a爰片久久| 一区二区中文| 免费超爽大片黄| 亚洲欧美不卡| 国产视频手机在线播放| 久久99国产精品免费网站| 中文字幕欧美视频| 成人精品视频网站| 性久久久久久久久久| 国产日韩欧美不卡在线| 国产精品精品软件男同| 亚洲激情成人在线| 国产成人愉拍精品久久| 欧美自拍丝袜亚洲| 97精品久久人人爽人人爽| 精品美女一区二区三区| 黄色片免费在线| 久久国产一区二区三区| 老司机福利av| 欧美人妖在线| 午夜精品一区二区三区四区| 亚洲三级网页| 中文字幕av导航| 亚洲视频播放| 久久国产精品国产精品| 国产成a人亚洲精| 国产中年熟女高潮大集合| 中文字幕制服丝袜成人av| 国产无遮挡又黄又爽在线观看| 色视频一区二区| www.com欧美| 永久555www成人免费| 欧美极品少妇videossex| 国产97在线|亚洲| 亚洲精品影片| 日本视频精品一区| 欧美日韩一区自拍| 成年人视频在线免费| 韩国欧美一区二区| 亚洲国产果冻传媒av在线观看| 国产亚洲综合色| 国产亚洲色婷婷久久99精品| 在线免费观看一区| 欧美熟妇交换久久久久久分类 | 亚洲永久精品ww.7491进入| 日韩毛片精品高清免费| 亚洲久久在线观看| 欧美一区二区三区白人| 福利视频在线看| 久久久女女女女999久久| 草民电影神马电影一区二区| 国产日韩一区欧美| 欧美a级片网站| 高清一区在线观看| 2020国产成人综合网| 真实国产乱子伦对白在线| 精品视频全国免费看| 性xxxx视频| 另类色图亚洲色图| 欧美三级精品| 久久久久无码国产精品一区| 亚洲无吗在线| xxxx视频在线观看| 综合久久给合久久狠狠狠97色| 五月婷婷激情视频| 亚洲高清在线观看| 日皮视频在线观看| 成人黄色免费在线观看| 欧洲激情视频| 国产精品动漫网站| 99国产精品一区| 国产精品第108页| 精品美女一区二区| 香蕉久久aⅴ一区二区三区| 亚洲va电影大全| 久久精品国产www456c0m| 免费一级特黄录像| 国产三级一区二区| 欧美人一级淫片a免费播放| 亚洲精品一区二区三区不| 黄色激情在线播放| 国内精品二区| 在线亚洲自拍| 在线观看av中文字幕| 五月开心婷婷久久| 偷拍精品一区二区三区| 91精品国产91久久久久久不卡| 国产精品调教| 丁香花在线影院观看在线播放| 丁香六月久久综合狠狠色| 久久久国产精品黄毛片| 精品国产一区二区亚洲人成毛片| 免费在线观看av电影| 国产精品swag| 国产精品久久国产愉拍| 亚洲中文字幕无码av| 天天av天天翘天天综合网色鬼国产| 十八禁一区二区三区| 97在线日本国产| 亚洲天堂日韩在线| 色七七在线观看| 国产精品久久久久久久裸模| 97人妻一区二区精品免费视频| 日韩中文字幕在线免费观看| 韩国三级大全久久网站| 成人小视频在线观看免费| 波波电影院一区二区三区| 中文字幕亚洲精品一区| 亚洲美女又黄又爽在线观看| 肉色欧美久久久久久久免费看| 亚洲国产精品视频一区| 国产制服丝袜一区| 久久精品视频国产| 国产视频精品久久久| 丰满少妇一区| 中国女人做爰视频| av电影在线观看一区| 黄色一级视频免费看| 日韩视频亚洲视频| av不卡一区二区| 日韩精品一区二区三区不卡| 国产精品成人免费| 免费观看成年人视频| 日韩免费高清在线观看| 99精品视频在线观看播放| 99久久久无码国产精品性波多 | 国产理论片在线观看| 韩国三级日本三级少妇99| 欧美久久综合网| 中文字幕在线观看91| 日本精品一级二级| 污污在线观看| 日韩福利视频| 国产不卡视频一区二区三区| 久草视频一区二区| 欧美俄罗斯乱妇| 精品香蕉视频| 亚洲综合久久久久| 三级视频在线播放| 成人性生交大片免费观看嘿嘿视频| 在线日韩欧美| 中文字幕无码日韩专区免费| 日韩不卡在线观看| 欧美成人一级|