目錄
判斷問題SQL
優化案例
首頁 資料庫 mysql教程 用實例告訴你該如何最佳化SQL

用實例告訴你該如何最佳化SQL

Aug 04, 2021 am 09:26 AM
sql優化

雖然現今硬體成本已經下降,透過升級硬體提升系統效能也是常用的最佳化方式。而即時性需求很高的系統,還是要從sql方面來優化,今天我們從實例的出發,介紹該如何優化SQL。

判斷問題SQL

判斷SQL是否有問題時可以透過兩個表象來判斷:

  • 系統層級表象

    • CPU消耗嚴重

    • IO等待嚴重

    • 頁面回應時間過長

    • #應用的日誌出現逾時等錯誤

可以使用sar指令,top指令查看目前系統狀態。也可以透過Prometheus、Grafana等監控工具觀察系統狀態。

用實例告訴你該如何最佳化SQL

  • SQL語句表象

    • 冗長

    • ##執行時間過長

    • 從全表掃描取得資料

    • #執行計畫中的rows、cost很大

冗長的SQL都好理解,一段SQL太長閱讀性一定會差,而且出現問題的頻率一定會更高。更進一步判斷SQL問題就得從執行計劃入手,如下所示:

用實例告訴你該如何最佳化SQL

#執行計劃告訴我們本次查詢走了全表掃描Type=ALL,rows很大(9950400)基本上可以判斷這是一段"有味道"的SQL。

取得問題SQL

不同資料庫有不同的取得方法,以下為目前主流資料庫的慢查詢SQL取得工具

  • MySQL

    • #慢查詢日誌

    • #測試工具loadrunner

    • #Percona公司的ptquery等工具

  • #Oracle

    • AWR報告

    • 測試工具loadrunner等

    • 相關內部視圖如v$、$session_wait等

    • GRID CONTROL監控工具

  • 達夢資料庫

    • AWR報告

    • #測試工具loadrunner等

    • 達夢效能監控工具(dem)

    • 相關內部視圖如v$、$session_wait等

SQL編寫技巧

SQL寫有以下幾個通用的技巧:

• 合理使用索引

#索引少了查詢慢;索引多了佔用空間大,執行增刪改語句的時候需要動態維護索引,影響效能選擇率高(重複值少)且被where頻繁引用需要建立B樹索引;

一般join列需要建立索引;複雜文件類型查詢採用全文索引效率較好;索引的建立要在查詢和DML效能之間取得平衡;複合索引建立時要注意基於非前導列查詢的情況

• 使用UNION ALL替代UNION

UNION ALL的執行效率比UNION高,UNION執行時需要排重;UNION需要對資料進行排序

• 避免select * 寫法

執行SQL時最佳化器需要將* 轉成具體的列;每次查詢都要回表,不能走覆蓋索引。

• JOIN欄位建議建立索引

一般JOIN欄位都提前加上索引

• 避免複雜SQL語句

提升可閱讀性;避免慢查詢的機率;可以轉換成多個短查詢,用業務端處理

• 避免where 1=1寫法

• 避免order by rand()類似寫法

RAND()導致資料列被多次掃描

SQL最佳化

執行計畫

完成SQL最佳化一定要先讀執行計劃,執行計劃會告訴你哪些地方效率低,哪裡可以需要最佳化。我們以MYSQL為例,看看執行計畫是什麼。 (每個資料庫的執行計劃都不一樣,需要自行了解)

用實例告訴你該如何最佳化SQL

欄位 解釋
#id 每個都獨立執行的操作標識,標識物件被操作的順序,id值越大,先被執行,如果相同,執行順序從上到下
select_type 查詢中每個select 字句的類型
table 被操作的物件名稱,通常是表名,但有其他格式
partitions 符合的分割區資訊(對於非分割表值為NULL)
#type 連線作業的型別
possible_keys 可能用到的索引
#key 優化器實際使用的索引(最重要的欄位)從最好到最糟糕的連接類型為const、eq_reg、ref、range、index和ALL。當出現ALL時表示目前SQL出現了「壞味道」
key_len 被最佳化器選定的索引鍵長度,單位是位元組
ref 表示本行被操作對象的參考對象,無參考物件為NULL
rows 查詢執行所掃描的元組個數(對於innodb,此值為估計值)
#filtered 條件表上資料被篩選的元組個數百分比
extra 執行計劃的重要補充信息,當此列出現Using filesort , Using temporary 字樣時就要小心了,很可能SQL語句需要優化

接下來我們用一段實際最佳化案例來說明SQL優化的流程及最佳化技巧。

優化案例

表格結構

CREATE TABLE `a`
(
    `id`          int(11) NOT NULLAUTO_INCREMENT,
    `seller_id`   bigint(20)                                       DEFAULT NULL,
    `seller_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
    `gmt_create`  varchar(30)                                      DEFAULT NULL,
    PRIMARY KEY (`id`)
);
CREATE TABLE `b`
(
    `id`          int(11) NOT NULLAUTO_INCREMENT,
    `seller_name` varchar(100) DEFAULT NULL,
    `user_id`     varchar(50)  DEFAULT NULL,
    `user_name`   varchar(100) DEFAULT NULL,
    `sales`       bigint(20)   DEFAULT NULL,
    `gmt_create`  varchar(30)  DEFAULT NULL,
    PRIMARY KEY (`id`)
);
CREATE TABLE `c`
(
    `id`         int(11) NOT NULLAUTO_INCREMENT,
    `user_id`    varchar(50)  DEFAULT NULL,
    `order_id`   varchar(100) DEFAULT NULL,
    `state`      bigint(20)   DEFAULT NULL,
    `gmt_create` varchar(30)  DEFAULT NULL,
    PRIMARY KEY (`id`)
);
登入後複製

三張表關聯,查詢當前用戶在當前時間前後10個小時的訂單情況,並根據訂單創建時間升序排列,具體SQL如下

select a.seller_id,
       a.seller_name,
       b.user_name,
       c.state
from a,
     b,
     c
where a.seller_name = b.seller_name
  and b.user_id = c.user_id
  and c.user_id = 17
  and a.gmt_create
    BETWEEN DATE_ADD(NOW(), INTERVAL – 600 MINUTE)
    AND DATE_ADD(NOW(), INTERVAL 600 MINUTE)
order by a.gmt_create;
登入後複製

查看資料量  

用實例告訴你該如何最佳化SQL

#原始執行時間

用實例告訴你該如何最佳化SQL

##原始執行計畫

用實例告訴你該如何最佳化SQL

初步最佳化想法


  1. #SQL中where條件欄位類型要跟表結構一致,表中    user_id 為varchar( 50)型,實際SQL用的int型,存在隱式轉換,也未加入索引。將b和c表     user_id 欄位改為int型別。

  2. 因存在b表和c表關聯,將b和c表    user_id建立索引

  3. 因存在a表和b表關聯,將a和b表    seller_name欄位建立索引

  4. 使用複合索引消除臨時表和排序

初步最佳化SQL

#

alter table b modify `user_id` int(10) DEFAULT NULL;
alter table c modify `user_id` int(10) DEFAULT NULL;
alter table c add index `idx_user_id`(`user_id`);
alter table b add index `idx_user_id_sell_name`(`user_id`,`seller_name`);
alter table a add index `idx_sellname_gmt_sellid`(`gmt_create`,`seller_name`,`seller_id`);
登入後複製
 查看優化後執行時間

用實例告訴你該如何最佳化SQL

查看優化後執行計劃


用實例告訴你該如何最佳化SQL

查看warnings資訊


用實例告訴你該如何最佳化SQL

繼續優化alter table a modify "gmt_create" datetime DEFAULT NULL;


查看執行時間


用實例告訴你該如何最佳化SQL

查看執行計劃


用實例告訴你該如何最佳化SQL

總結


  1. 查看執行計劃explain

  2. 如果有警告訊息,請查看警告訊息show warnings;

  3. 查看SQL涉及的資料表結構和索引訊息

  4. 根據執行計劃,思考可能的最佳化點

  5. 依照可能的最佳化點執行表格結構變更、增加索引、SQL改寫等操作

  6. 查看優化後的執行時間和執行計劃

  7. 如果最佳化效果不明顯,重複第四步驟操作

相關推薦:《

mysql教學

以上是用實例告訴你該如何最佳化SQL的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
2 週前 By 尊渡假赌尊渡假赌尊渡假赌
倉庫:如何復興隊友
4 週前 By 尊渡假赌尊渡假赌尊渡假赌
Hello Kitty Island冒險:如何獲得巨型種子
3 週前 By 尊渡假赌尊渡假赌尊渡假赌

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何優化Discuz論壇性能? 如何優化Discuz論壇性能? Mar 12, 2024 pm 06:48 PM

如何優化Discuz論壇性能?

如何優化SQL Server和MySQL的效能,讓它們發揮最佳水準? 如何優化SQL Server和MySQL的效能,讓它們發揮最佳水準? Sep 11, 2023 pm 01:40 PM

如何優化SQL Server和MySQL的效能,讓它們發揮最佳水準?

Linux效能調優~ Linux效能調優~ Feb 12, 2024 pm 03:30 PM

Linux效能調優~

Sybase與Oracle資料庫管理系統的核心差異 Sybase與Oracle資料庫管理系統的核心差異 Mar 08, 2024 pm 05:54 PM

Sybase與Oracle資料庫管理系統的核心差異

sql中any是什麼意思 sql中any是什麼意思 May 01, 2024 pm 11:03 PM

sql中any是什麼意思

MySql的SQL語句執行計畫:如何最佳化MySQL的查詢過程 MySql的SQL語句執行計畫:如何最佳化MySQL的查詢過程 Jun 16, 2023 am 09:15 AM

MySql的SQL語句執行計畫:如何最佳化MySQL的查詢過程

在PHP開發中如何最佳化SQL查詢操作 在PHP開發中如何最佳化SQL查詢操作 Jun 25, 2023 am 11:43 AM

在PHP開發中如何最佳化SQL查詢操作

如何實現MySQL底層優化:SQL語句優化的常見技巧與原則 如何實現MySQL底層優化:SQL語句優化的常見技巧與原則 Nov 08, 2023 pm 08:19 PM

如何實現MySQL底層優化:SQL語句優化的常見技巧與原則

See all articles