精品欧美一区二区三区在线观看 _久久久久国色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在线直播亚洲| www.久久久久久久| 欧美不卡在线| 日韩在线视频免费观看| 日本一区二区在线免费观看| 久久av影院| 午夜精品aaa| 中文网丁香综合网| 日韩三级电影网| 黑人巨大精品欧美黑白配亚洲| 91黑丝在线观看| 成人在线观看小视频| 欧美福利在线播放网址导航| 欧美高清一级片在线| 欧美视频第一区| 青草在线视频| 亚洲同性gay激情无套| 欧洲亚洲一区| 无套内谢的新婚少妇国语播放| 久久精品免费观看| 日本老师69xxx| 麻豆一区二区三区精品视频| 97国产成人高清在线观看| 亚洲精品中文字幕有码专区| 成人啪啪18免费游戏链接| 在线成人免费| 欧美视频在线播放| 欧美日韩亚洲一二三| 黄页在线观看免费| 亚洲品质自拍视频网站| 一区二区91美女张开腿让人桶| 色av男人的天堂免费在线| 成人看片黄a免费看在线| 亚洲一区免费网站| 国产精品久久久久久在线| 日本中文字幕不卡| 国产成人精品av在线| 亚洲男人的天堂在线视频| 国产精品观看| 欧美国产极速在线| 强行糟蹋人妻hd中文| 88国产精品视频一区二区三区| 这里精品视频免费| 中文字幕第二区| 激情综合网站| 国产一区二区三区欧美| 男人的天堂官网 | 91视频国产一区| 中国精品一区二区| 蜜臀av性久久久久av蜜臀妖精| 日韩av色综合| 中文字幕 国产精品| 日韩av网站免费在线| 国产精品女视频| 亚洲一区二区天堂| 国产一区二区伦理| 国产精品免费一区二区三区在线观看 | 一二三四视频在线中文| 欧美色视频日本版| 可以免费观看av毛片| www.一区| 欧美一区二区在线免费播放| 一级黄色大片免费看| 国产香蕉精品| 国产一区二区三区在线| 影音先锋男人资源在线观看| 亚洲精品成人无限看| 欧美国产日本高清在线| 国产精品久久久免费视频| 久久av一区| 成人在线国产精品| 色香蕉在线视频| 国产日韩欧美激情| 国产又爽又黄ai换脸| 超清av在线| 色婷婷av一区二区三区之一色屋| 精品亚洲一区二区三区四区| 视频一区日韩| 亚洲人成在线一二| 日本少妇高清视频| 亚洲一区国产| 成人av在线天堂| 手机在线观看免费av| 国产欧美日本一区二区三区| 一区二区高清视频| 韩日毛片在线观看| 色欧美片视频在线观看在线视频| 日韩a一级欧美一级| 啪啪激情综合网| 久久久www成人免费精品| 91国产丝袜播放在线| 蜜臀av性久久久久蜜臀aⅴ流畅| 成人蜜桃视频| 91精彩在线视频| 天天综合天天做天天综合| 国产日韩欧美久久| 先锋影音国产精品| 久久97精品久久久久久久不卡| 日韩精品久久久久久免费| 国产揄拍国内精品对白| 日本视频一区在线观看| 成人av影院在线观看| 欧美精品乱码久久久久久按摩| 自拍视频一区二区| 欧美日本不卡高清| 国产日韩欧美在线播放| 精品99又大又爽又硬少妇毛片 | 国产激情在线看| yiren22亚洲综合| 日韩精品www| 九九九免费视频| 国内一区二区视频| 日韩欧美在线观看强乱免费| 国产高清视频色在线www| 日韩欧美的一区二区| 成人欧美一区二区三区黑人一| 国产精品毛片在线| 国产精品成人一区二区三区| 国产精品一卡二卡三卡| 欧美日韩在线播放三区四区| 亚洲第一成人网站| 在线亚洲激情| 国产欧美丝袜| 国产丝袜视频在线播放| 日韩一级免费一区| √天堂中文官网8在线| 免费观看久久久4p| 亚洲精品一区二区毛豆| 欧美三级精品| 亚洲一二三在线| 中文字幕在线播| 久久日韩粉嫩一区二区三区| 欧美亚洲一二三区| 四虎5151久久欧美毛片| 午夜精品一区二区三区在线视频 | 国产绿帽刺激高潮对白| 国产精品蜜臀av| 日韩一级理论片| 国产精品自拍区| 日韩av手机在线| 国产污视频在线| 欧美性做爰猛烈叫床潮| 精品人妻一区二区三区四区| 日韩和的一区二区| 深田咏美在线x99av| 日本在线精品| 色偷偷噜噜噜亚洲男人| 国产精品自产拍| 亚洲精品午夜久久久| a级大片免费看| 激情成人综合| 久久天天狠狠| h1515四虎成人| 久久精品这里热有精品| www.天堂av.com| 亚洲va天堂va国产va久| 给我看免费高清在线观看| 日韩国产精品久久久| 日韩一本精品| 亚洲精品影片| 日韩女优在线播放| 麻豆视频免费在线观看| 精品嫩草影院久久| 中文字幕黄色片| 亚洲欧洲成人自拍| 久久久老熟女一区二区三区91| 噜噜爱69成人精品| 亚洲精品国产一区| 一区二区三区免费在线看| 91禁外国网站| 日韩黄色影院| 精品国产乱码久久久久久闺蜜| 免费看毛片网站| 日韩美女久久久| 无码一区二区精品| 日本网站在线观看一区二区三区| 超碰10000| 免费短视频成人日韩| 成人国产精品久久久| 9765激情中文在线| 日韩午夜在线视频| 神马午夜一区二区| 欧美日本高清视频在线观看| 日本熟妇乱子伦xxxx| 亚洲国产精品成人综合色在线婷婷| 深爱五月综合网| 久久久天天操| 国产一级不卡视频| 欧美午夜精彩| 国产精品久久久久久久久久直播 | 欧美tickling挠脚心丨vk| 波多野结衣视频网站| 中文字幕一区二区5566日韩| 亚洲av无码一区东京热久久| 麻豆国产欧美日韩综合精品二区| 极品粉嫩国产18尤物| 婷婷伊人综合| 日本精品二区| 久久久久久毛片免费看 | 国产精品视频资源| 国产激情在线播放| 欧美精品午夜视频| av在线电影网| 亚洲精品资源美女情侣酒店| 精品二区在线观看| 欧美视频一区二区三区在线观看| 亚欧洲精品在线视频| 亚洲视频在线观看三级| 午夜时刻免费入口| 成人精品gif动图一区| 网站在线你懂的| 日本成人在线不卡视频| 免费在线a视频| 在线精品在线| 日本精品福利视频| 91精品二区| 亚洲精品久久区二区三区蜜桃臀| 美女亚洲一区| 蜜桃久久影院| 西野翔中文久久精品字幕| 国精产品一区二区| 亚洲一二av| 超碰97国产在线| 亚洲综合色婷婷在线观看| 91美女片黄在线观| www一区二区三区| 91久久在线视频| 国产精品白丝久久av网站| 成人午夜激情免费视频| 日韩专区视频| 国产欧美日韩专区发布| 黑人一区二区三区| 国产精品入口尤物| 香蕉久久一区| 亚洲一区二区三区成人在线视频精品| 欧美一级在线| 国产在线观看精品一区二区三区| 成人在线免费电影网站| 国产精品一区电影| 高清一区二区| 超碰97在线资源| 噜噜噜天天躁狠狠躁夜夜精品| 国产精品我不卡| 欧美色图婷婷| 免费国产一区二区| 成人情趣视频网站| 中文字幕欧美日韩一区二区三区| 亚洲男女av一区二区| 久久久99精品视频| 国产精品久久久久9999高清| 欧美少妇性生活视频| 男人的j进女人的j一区| 亚洲天堂av一区二区| 国产精品自拍网站| 这里只有精品在线观看视频 | 美女任你摸久久| 日韩成人av免费| 成人av网站免费| 四虎影成人精品a片| 国产精品免费av| 国语对白一区二区| 日本韩国一区二区| 国产伦精品一区二区三区视频痴汉 | 色综合天天综合网中文字幕| 亚洲色婷婷久久精品av蜜桃| 国产精品三上| 中文字幕在线视频精品| 成人禁用看黄a在线| 亚洲第一综合网| 一区二区三区不卡视频在线观看| 日韩熟女精品一区二区三区| 欧美性猛交xxxxxxxx| 精品黑人一区二区三区在线观看 | 男人操女人动态图| 成人欧美一区二区三区在线播放| 日本一二三区不卡| 欧美视频三区在线播放| 亚洲第九十九页| 中文字幕亚洲无线码在线一区| 色噜噜狠狠狠综合欧洲色8| 日本一区二区在线播放| 欧美高清hd| 日韩欧美精品一区二区| 伊人天天综合| 国产永久免费网站| ww亚洲ww在线观看国产| 综合五月激情网| 色狠狠av一区二区三区| 不卡视频在线播放| 国产一区二区三区欧美| 多野结衣av一区| 亚洲一区二区三区在线免费观看| 视频一区中文| 999在线观看视频| 国产一区二区三区久久久 | 在线观看中文av| 久久精品视频在线看| 国产精品第56页| 7777女厕盗摄久久久| 国内三级在线观看| 97国产精品免费视频| 美女精品久久| 一区二区三区在线视频111| 香港一级纯黄大片| 久久美女高清视频| 国产在线拍揄自揄拍无码视频| 欧美制服丝袜第一页| 欧美自拍偷拍第一页| 久热精品视频在线观看一区| 亚洲综合av一区二区三区| 好吊色欧美一区二区三区视频| 最新国产精品| 天天综合天天添夜夜添狠狠添| 国产人成亚洲第一网站在线播放| 亚洲免费激情视频| 亚洲爱爱爱爱爱| 在线免费av导航| 亚洲aaaaaa| 91偷拍一区二区三区精品| 欧美三级理论片| 亚洲国产精品av| av图片在线观看| 亚洲男人天堂网站| 在线男人天堂| 你懂的网址一区二区三区| 99pao成人国产永久免费视频| 国产香蕉精品视频| 亚洲综合一区在线| 国产成人三级在线观看视频| 色综合久久中文字幕综合网小说| 91成人在线网站| 国产又粗又长又爽视频| 国产一区二区三区在线观看免费| 特一级黄色录像| 欧美一区二区私人影院日本| 18视频在线观看网站| 亚洲一区二区三区四区在线播放 | 少妇av一区二区三区无码| 国产91丝袜在线播放0| 久久久久久蜜桃| 亚洲激情第一页| 桃色av一区二区| 日韩啊v在线| 久草在线在线精品观看| 日韩欧美国产成人精品免费| 日韩一区二区中文字幕| 日本高清在线观看| 精品人伦一区二区三区 | 91丝袜超薄交口足| 夜夜精品浪潮av一区二区三区| 狠狠躁日日躁夜夜躁av| 668精品在线视频| 国产欧美日韩视频在线| 久久婷五月综合| 亚洲免费av观看| 人妻夜夜爽天天爽| 国产精品成人久久久久| 99精品视频在线观看播放| 欧美高清精品一区二区| 亚洲444eee在线观看| 理论视频在线| 91久久精品国产| 在线观看日韩av电影| 人与嘼交av免费| 91麻豆精品国产| 日本在线高清| 亚洲精品影院| 国产91精品在线观看| 国产一级片毛片| 久久久av一区| 日韩av中文字幕一区| youjizzxxxx18| 亚洲影视在线播放| 国产高清视频免费最新在线| 亚洲综合日韩中文字幕v在线| 亚洲第一黄网| 婷婷社区五月天| 国产在线精品不卡| 日韩精品福利片午夜免费观看| 国产经典欧美精品| 婷婷激情五月网| 久久综合色影院| 欧美**vk| 蜜桃色一区二区三区| 91福利国产精品| 2021中文字幕在线| 一区二区三区日韩视频| 久久精品一区二区三区不卡牛牛 | 精品国产1区二区| 青青国产精品| 国产美女三级视频|