Sql性能優化看這一篇就夠了

2022-01-17 終端研發部

點擊上方藍色「終端研發部」,選擇「設為星標」

前言:

一個優秀開發的必備技能:性能優化,包括:JVM調優、緩存、Sql性能優化等。本文主要講基於Mysql的索引優化。
首先我們需要了解執行一條查詢SQL時Mysql的處理過程:

其次我們需要知道,我們寫的SQL在Mysql的執行順序是怎麼樣的?sql的執行順序對sql的性能優化很有幫助,很重要。在建立複合索引的時候需要考慮到這點。

例:

在tb_dept中建立一個複合索引 idx_parent_id_code:

然後看下兩個sql 解釋的結果:

1)在當前索引下,哪一個sql索引利用率高?

藉助於上文中查詢SQL的執行順序,是先執行 WHERE再執行 GROUP BY 的,即:

第一個sql執行的順序是先執行了 where後的 parent_id然後執行了 group by 後的 dept_code,順序是和索引的順序是一致的,type等級為ref,掃描行數rows為 4;

而第二個sql是先執行了 where後的 dept_code然後執行了 group by 後的 parent_id,順序是和索引的順序是不一致的,type等級為index,掃描行數rows為 19;

從解釋結果看,第一條的sql索引利用率高於第二條的。(後文會講到:索引type從優到差:System→const→eq_ref→ref-->ref_or_null→index_merge→unique_subquery→index_subquery→range→index-->all.)

或者從掃描的行數rows對比數據源也可直觀的看出,兩個語句的性能:

2)怎麼優化?

如果業務中用到第二個sql,那麼就需要調整索引的順序和sql執行順序一致。

或者兩個sql都用到了,那麼就再建一個複合索引 (idx_code_parent_id)

然後再看下第二條的執行計劃:

執行計劃分析(下面就是本文的重點內容了):

通過explain可以知道mysql是如何處理語句的,並分析出查詢或是表結構的性能瓶頸,其實就是在幹查詢優化器的事,通過expalin可以得到:

1. 表的讀取順序
2.表的讀取操作的操作類型
3.哪些索引可以使用
4. 哪些索引被實際使用
5.表之間的引用
6.每張表有多少行被優化器查詢

從上文的例子中我們可以看到執行explain時,結果會有一個表格,這個表格就是分析結果,下面我們來一個一個說明下這個表的表頭:

Id: MySQL QueryOptimizer 選定的執行計劃中查詢的序列號。表示查詢中執行select 子句或操作表的順序,id 值越大優先級越高,越先被執行。id 相同,執行順序由上至下。

Select_type: 一共有9中類型,只介紹常用的4種:

SIMPLE: 簡單的 select 查詢,不使用 union 及子查詢

PRIMARY: 最外層的 select 查詢

UNION: UNION 中的第二個或隨後的 select 查詢,不 依賴於外部查詢的結果集

DERIVED: 用於 from 子句裡有子查詢的情況。MySQL 會 遞歸執行這些子查詢, 把結果放在臨時表裡。

Table: 輸出行所引用的表

Type: 從優到差的順序如下:(紅色標識的是常見的級別。)

system→const→eq_ref→ref-->ref_or_null→index_merge→unique_subquery→index_subquery→range→index→all.

各自的含義如下:

system: 表僅有一行。這是 const 連接類型的一個特例。

const: const 用於用常數值比較 PRIMARY KEY 時。

eq_ref: 查詢使用了索引為主鍵或唯一鍵的全部時使用。即:通過索引關鍵字可能查找到一個符合條件的行。

ref: 通過索引關鍵字可能查找到多個符合條件的行。

ref_or_null: 如同 ref, 但是 MySQL 必須在初次查找的結果裡找出 null 條目,然後進行二次查找。

index_merge: 說明索引合併優化被使用了。

unique_subquery: 在某些 IN 查詢中使用此種類型,而不是常規的 ref:valueIN (SELECT primary_key FROM single_table WHERE some_expr)

index_subquery: 在 某 些 IN 查 詢 中 使 用 此 種 類 型 , 與unique_subquery 類似,但是查詢的是非唯一 性索引

range: 檢索給定範圍的行。當使用 <>、>、>=、<、<=、BETWEEN 或者 IN 操作符時,會使用到range。

index: 全表掃描,只是掃描表的時候按照索引次序進行而不是行。主要優點就是避免了排序, 但是開銷仍然非常大。

all: 最壞的情況,從頭到尾全表掃描。

possible_keys : 哪些索引可能有助於查詢。如果為空,說明沒有可用的索引。

key: 實際從 possible_key 選擇使用的索引,如果為 NULL,則沒有使用索引。很少的情況 下,MYSQL 會選擇優化不足的索引。這種情 況下,可以在 SELECT語句中使用 USE INDEX (indexname)來強制使用一個索引或者用IGNORE INDEX(indexname)來強制 MYSQL 忽略索引

key_len: 使用的索引的長度。在不損失精確性的情況 下,長度越短越好。

ref: 顯示索引的哪一列被使用了

rows: 請求數據返回的大概行數

extra: 其他信息,出現Using filesort、Using temporary 意味著不能使用索引,效率會受到重大影響。應儘可能對此進行優化。

Using filesort: 沒有辦法利用現有索引進行排序,需要額外排序,建議:根據排序需要,創建相應合適的索引

Using temporary: 需要用臨時表存儲結果集,通常是因為group by的列列上沒有索引。也有可能是因為同
時有group by和order by,但group by和order by的列又不一樣

Using index :利用覆蓋索引,無需回表即可取得結果數據(即數據直接從索引文件中讀取),這種結果是好的。

其中重要的幾個就是 key、type 、rows、extra,其中key為null、all 、index時,需要調整、優化索引。一般需要達到 ref、eq_ref 級別,範圍查找需要達到 range,extra有Using filesort、Using temporary 的一定需要優化,根據rows可以直觀看出優化結果。

優化手段:

① SQL優化

避免 SELECT *,只查詢需要的欄位。

小表驅動大表,即小的數據集驅動大的數據集:
當B表的數據集比A表小時,用in優化 exist兩表執行順序是先查B表再查A表查詢語句:SELECT * FROM tb_dept WHERE id in (SELECT id FROM tb_dept) ;
當A表的數據集比B表小時,用exist優化in ,兩表執行順序是先查A表,再查B表,查詢語句:SELECT * FROM A WHERE EXISTS (SELECT id FROM B WHERE A.id = B.ID) ;

儘量使用連接代替子查詢,因為使用 join 時,MySQL 不會在內存中創建臨時表。

② 優化索引的使用

儘量使用主鍵查詢,而非其他索引,因為主鍵查詢不會觸發回表查詢。

不做列運算,把計算都放入各個業務系統實現

查詢語句儘可能簡單,大語句拆小語句,減少鎖時間

or 查詢改寫成 union 查詢

不用函數和觸發器

避免 %xx 查詢,可以使用:select * from t where reverse(f) like reverse(『%abc』);

少用 join 查詢

使用同類型比較,比如 『123』 和 『123』、123 和 123

儘量避免在 where 子句中使用 != 或者 <> 操作符,查詢引用會放棄索引而進行全表掃描

列表數據使用分頁查詢,每頁數據量不要太大

避免在索引列上使用 is null 和 is not null

③ 表結構設計優化

使用可以存下數據最小的數據類型。

儘量使用 tinyint、smallint、mediumint 作為整數類型而非 int。

儘可能使用 not null 定義欄位,因為 null 佔用 4 字節空間。數字可以默認 0 ,字符串默認 「」

儘量少用 text 類型,非用不可時最好獨立出一張表。

儘量使用 timestamp,而非 datetime。

單表不要有太多欄位,建議在 20 個欄位以內。

Mysql常用數據類型存儲大小及範圍:https://blog.csdn.net/HXNLYW/article/details/100104768

3.如果以上優化還是有問題,可以使用show profiles 分析sql 性能

show profiles

show profile for query [queryId]

具體請查看:https://blog.csdn.net/aeolus_pu/article/details/7818498

結尾:

本文是最近學習Mysql索引優化的一些總結和記錄,如有不對的地方,歡迎評論吐槽。

附:

索引相關知識:

———— 查看表索引:
show index from 【table】

———— 直接創建索引
CREATE INDEX indexName ON table(column(length))

———— 修改表結構的方式添加索引
ALTER tableADD INDEX indexName ON (column(length))
-—主鍵索引
ALTER TABLE `table_name` ADD PRIMARY KEY ( `column` )
-—唯一索引
ALTER TABLE `table_name` ADD UNIQUE (`column` )
-—普通索引
ALTER TABLE `table_name` ADD INDEX index_name ( `column`(length) )
-—複合索引
ALTER TABLE `table_name` ADD INDEX index_name ( `column1`, `column2`, `column3` )

length的確定:
如果索引列長度過長,這種列索引時將會產生很大的索引文件,不便於操作,可以使用前綴索引方式進行索引,前綴索引應該控制在一個合適的點,控制在0.31黃金值即可(大於這個值就可以創建)。
SELECT COUNT(DISTINCT(LEFT(`title`,10)))/COUNT(*) FROM Arctic; — 這個值大於0.31就可以創建前綴索引,Distinct去重複

———— 刪除索引:
1)ALTER TABLE table_name DROP INDEX index_name
2)DROP INDEX index_name ON table_name;

MyISAM 和 InnoBD區別:

mysql相關配置參數優化:

• sort-buffer-size/join-buffer-size / read-rnd-buffer-size,4~8MB為宜
• optimizer_switch=「index_condition_pushdown=on,mrr=on,mrr_cost
_based=off,batched_key_access=on」
• tmp-table-size = max-heap-table-size,100MB左右為宜
• log-queries-not-using-indexes & log_throttle_queries_not_using_indexes

作者:葫蘆胡
連結:https://blog.csdn.net/HXNLYW/article/details/82979088
 

BAT等大廠Java面試經驗總結

想獲取 Java大廠面試題學習資料

掃下方二維碼回復「BAT」就好了

回復 【加群】獲取github掘金交流群

回復 【電子書】獲取2020電子書教程

回復 【C】獲取全套C語言學習知識手冊

回復 【Java】獲取java相關的視頻教程和資料

回復 【爬蟲】獲取SpringCloud相關多的學習資料

回復 【Python】即可獲得Python基礎到進階的學習教程

回復 【idea破解】即可獲得intellij idea相關的破解教程關注我gitHub掘金,每天發掘一篇好項目,學習技術不迷路!

回復 【idea激活】即可獲得idea的激活方式

回復 【Java】獲取java相關的視頻教程和資料

回復 【SpringCloud】獲取SpringCloud相關多的學習資料

回復 【python】獲取全套0基礎Python知識手冊

回復 【2020】獲取2020java相關面試題教程

回復 【加群】即可加入終端研發部相關的技術交流群

閱讀更多

相信自己,沒有做不到的,只有想不到的

在這裡獲得的不僅僅是技術!


喜歡就給個「在看

相關焦點

  • SQL子查詢優化,看這一篇就夠了
    子查詢(Subquery)的優化一直以來都是 SQL 查詢優化中的難點之一。關聯子查詢的基本執行方式類似於 Nested-Loop,但是這種執行方式的效率常常低到難以忍受。如果出現在 WHERE 中,這就是我們熟悉的 Semi-Join。當然,它可能出現在任何可以放布爾值的地方。
  • MyBatis 的執行流程,看這一篇就夠了!
    3、然後會繼續調用自己的parseConfiguration來解析配置文件,這裡面就會分別去解析全局配置文件的頂級節點,其他的我們先不看,我們直接看最後解析mappers節點整個sql執行流程可以分為兩大步驟:首先還是來看一下尋找sql語句的時序圖:
  • flink sql 知其所以然(六)| flink sql 約會 calcite(看這篇就夠了)
    感謝您的小愛心(關注  +  點讚 + 再看),對博主的肯定,會督促博主持續的輸出更多的優質實戰內容!!!1.序篇-本文結構全網第一個 flink sql 實戰,本文主要介紹 flink sql 與 calcite 之間的關係。flink sql 的解析主要依賴 calcite。
  • 區間檢索SQL性能優化方法
    編輯手記:RWP(Real World Performance)團隊是全球最優秀的性能優化團隊,他們的目標在於系統性能千倍的提升
  • 看這一篇就夠!
    比如給老總們看的報表,用於進行市場開拓的用戶行為統計,不同維度的匯總分析結果等等。操作主體一般是運營、銷售和市場等團隊人員而不是用戶。單次OLTP處理的數據量比較小,所涉及的表非常有限,一般僅一兩張表。
  • SQL性能優化策略之索引優化方法
    優化是優化工作中經常會涉及的問題,由於早期的開發人員往往只關注於SQL功能的實現,而忽略了性能。本文為大家介紹一些生產環境中真實的常用索引優化方法。整個SQL語句最終返回的行數為個位數,C表通過YZ_ZXRQ_IDX索引範圍掃描再回表進行過濾,獲取綁定變量值,之後再進一步確認C表返回的行數,代碼如下:SQL> select sql_Id, name, datatype_string, last_captured, value_string from v$sql_bind_capture
  • NoSQL 還是 SQL ?這一篇講清楚
    在優勢方面,主要體現在下面這三點: 簡單的擴展:典型例子是Cassandra,由於其架構是類似於經典的P2P,所以能通過輕鬆地添加新的節點來擴展這個集群; 快速的讀寫:主要例子有Redis,由於其邏輯簡單,而且純內存操作,使得其性能非常出色,單節點每秒可以處理超過10萬次讀寫操作; 低廉的成本:這是大多數分布式資料庫共有的特點,因為主要都是開源軟體
  • SSD性能怎麼測?看這一篇就夠了!
    具體過程網上和書本裡很多這方面介紹,這裡就不贅述了。我們要知道的是,這其中每一環都會產生延遲損耗。在十幾年前,我們可以說這種損耗相對於普通的碟片存儲和早期SSD來說基本可以忽略不計。但是隨著硬體的發展,存儲設備的性能上升了幾個數量級,於是這些軟體的部分越來越不可以忽略,甚至開始爭奪性能的主導影響因素。
  • 優化一個rownum=1的sql
    這是某個客戶的BOSS系統中的一個top sql,SQL代碼如下:SELECT   t1.seq AS sequence ,t1.TemplateID AS templateId ,t1.parameter AS parameter ,t1.SERVICE_NO AS serviceNo ,trim(t1.phone_no) AS
  • 外貿網站SEO優化入門,看這一篇就夠了
    如果你對英文SEO優化感興趣,這篇文章絕對可以作為你自學的入門手冊,本文接近1萬字,看過的人都覺得很贊,支持一燈的話就轉發到你的朋友圈吧,讓更多人知道
  • 打工人的電腦設置及優化,只看這一篇就夠了!
    我們可以通過設置高性能的電源計劃,來優化電腦的性能。操作如下:通過快捷鍵WIN+R打開【運行】對話框。輸入「control」,點擊確定,進入控制面板。
  • SQL on Hadoop TPCDS性能測試
    3、Presto使用效率確實很不錯,但是需要做很多優化參數和底層文件大小考慮,還有一些內存有關參數調節,而且節點壓力太大會失去聯繫,技術性公司出的東西,對orc格式優化最多性能最優。4、Hive查詢hbase表,因為mapjion優化參數導致報錯問題?
  • Spark原理|Spark SQL 自適應執行優化引擎
    在之前的文章中,筆者介紹過 Flink SQL,目前 Flink 社區在積極地更新迭代 Flink SQL 功能和優化性能,尤其 Flink 1.10.0 版本的發布,在增強流式 SQL 處理能力的同時也具備了成熟的批處理能力。但是在 SQL 功能完整性和生產環境的實踐應用等方面,Spark SQL 還是更勝一籌,至於 SQL 批處理方面性能優劣,則需要筆者親自去實踐。
  • Git入門看這一篇就夠了!
    集中化的版本控制系統都有一個單一的集中管理的伺服器,保存所有文件的修訂版本,而協同工作的人們都通過客戶端連到這臺伺服器,取出最新的文件或者提交更新。下圖來源於Git官網。我後面會詳細介紹這兩種方式的差別。大部分版本控制系統(CVS、Subversion、Perforce、Bazaar 等等)都是以文件變更列表的方式存儲信息,這類系統將它們保存的信息看作是一組基本文件和每個文件隨時間逐步累積的差異。
  • 如何用一杯茶的功夫調優日誌搜尋引擎性能,看這一篇就夠了~
    OtterTune 的目的是為了幫助 DBA,讓資料庫部署和調優更加容易,用機器來代替資料庫調參這個冗繁但又很重要的工作,讓技術人員甚至不需要專業知識也能順利完成。OtterTune 分為客戶端和服務端,目標資料庫是用戶需要調優參數的資料庫:客戶端安裝在目標資料庫所在的機器上,收集目標資料庫的統計信息,並上傳到服務端。
  • SQL優化終於幹掉了「distinct」
    一、優化目的二、優化之前的sql長這樣三、DISTINCT關鍵字的用法四、談:如何優化distinct的sql五、distinct真的和group by等價嗎?六、優化後的sql長啥樣?七、總結一、優化目的在我提交了代碼的時候,架構師給我指出我這個sql這樣寫會有問題。因為在分庫分表的時候,是不支持子查詢的。
  • 看這一篇就夠啦!
    我沒有使用360的優化比如關閉系統休眠和移動虛擬內存目錄(進行以上2行為在我16g內存的情況下會解放32g的磁碟空間),而是讓系統以微軟設計默認的方式運作,所以會對磁碟空間要求高一些。自己有2臺臺式和1臺筆記本系統盤都是用的ssd,240g起步(由於我有在桌面存文件的壞習慣orz),平日的使用是足夠的,如果你和我一樣喜歡在桌面不分大小的丟東西,那麼240的容量是很好的選擇。
  • 香港必備APP | 實用齊全,看這一篇就夠了
    香港必備APP | 實用齊全,看這一篇就夠了通訊類💌:️WhatsApp
  • 瀏覽器緩存看這一篇就夠了
    (點擊上方公眾號,可快速關注一起學Python)作者:xc_xiang   原文連結:https://segmentfault.com/a/1190000018717463瀏覽器緩存作為性能優化的重要一環
  • 網絡虛擬化,看這一篇就夠了!
    不久之前有一篇《萬字長文:IP網絡的前浪和後浪》從網工的視角介紹了IP網絡的發展變化。其中最後推薦的Cisco的大牛的Silivano Gai 的《Building-Future-Proof-Cloud-Infrastructure-Architecture》的確值得一讀。