Mysql高級5-SQL優化

来源:https://www.cnblogs.com/Se7eN-HOU/archive/2023/07/31/17588038.html
-Advertisement-
Play Games

一、插入數據優化 1.1 批量插入 如果有多條數據需要同時插入,不要每次插入一條,然後分多次插入,因為每執行一次插入的操作,都要進行資料庫的連接,多個操作就會連接多次,而一次批量操作只需要連接1次 1.2 手動提交事務 因為Mysql預設每執行一次操作,就會提交一次事務,這樣就會涉及到頻繁的事務的開 ...


一、插入數據優化

  1.1 批量插入

    如果有多條數據需要同時插入,不要每次插入一條,然後分多次插入,因為每執行一次插入的操作,都要進行資料庫的連接,多個操作就會連接多次,而一次批量操作只需要連接1次

  1.2 手動提交事務

    因為Mysql預設每執行一次操作,就會提交一次事務,這樣就會涉及到頻繁的事務的開啟與關閉

start transaction;
  insert into 表名 values(),(),();
  insert into 表名 values(),(),();
  insert into 表名 values(),(),();
commit;

  1.3 主鍵順序插入

    主鍵一般是預設自增的,但是也可以手動增加,這裡不建議手動亂序增加,而是使用預設的順序增加,原因會在後面解釋。

  1.4 大批量插入數據

    如果一次性需要插入大批量數據,使用insert語句插入性能較低,此時可以使用Mysql資料庫提供的load指令進行插入,

    首先在連接資料庫的時候需要加上 --local-infile 參數

mysql --local-infile -u root -p

    在使用本地文件載入功能的時候,需要先查看本地載入文件選項是否開啟的

mysql> select @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              0 |
+----------------+
1 row in set (0.00 sec)

    說明1:0表示本地載入文件並未開啟

    開啟本地載入文件的語句

mysql> set global local_infile = 1;
Query OK, 0 rows affected (0.01 sec)

mysql> select @@local_infile;
+----------------+
| @@local_infile |
+----------------+
|              1 |
+----------------+
1 row in set (0.00 sec)

    創建一個空表tb_user,其表結構如下

mysql> desc tb_user;
+----------+-------------+------+-----+---------+----------------+
| Field    | Type        | Null | Key | Default | Extra          |
+----------+-------------+------+-----+---------+----------------+
| id       | int         | NO   | PRI | NULL    | auto_increment |
| username | varchar(50) | NO   | UNI | NULL    |                |
| password | varchar(50) | NO   |     | NULL    |                |
| name     | varchar(20) | NO   |     | NULL    |                |
| birthday | date        | YES  |     | NULL    |                |
| sex      | char(1)     | YES  |     | NULL    |                |
+----------+-------------+------+-----+---------+----------------+
6 rows in set (0.01 sec)

    使用load載入本地文件 'tb_user_data.sql' 內容到新創建的表中,其中tb_user_data.sql中的測試數據如下

houlei@houleideMacBook-Pro Desktop % cat tb_user_data.sql
1,a,aa,aaa,2023-07-01,1
2,b,bb,bbb,2023-07-02,0
3,c,cc,ccc,2023-07-03,1
4,d,dd,ddd,2023-07-04,0
5,e,ee,eee,2023-07-05,1
6,f,ff,fff,2023-07-06,0
7,g,gg,ggg,2023-07-07,1
houlei@houleideMacBook-Pro Desktop % 

    使用load載入本地文件 'tb_user_data.sql' 內容到新創建的表中  

mysql> load data local infile '/Users/houlei/Desktop/tb_user_data.sql' into table tb_user fields terminated by ',' lines terminated by '\n';
Query OK, 7 rows affected (0.01 sec)
Records: 7  Deleted: 0  Skipped: 0  Warnings: 0

    說明1: load data local infile 是載入本地文件的意思,

    說明2:'/Users/houlei/Desktop/tb_user_data.sql'是文件路徑

    說明3:into table tb_user 是將文件中的數據,插入到tb_user表中

    說明4:fields terminated by ',' 是說每個欄位之間的數據是使用','分割的

    說明5:lines terminated by '\n' 是說每一行之間的數據使用的是‘\n’分割的

    說明6:本方法只是舉例,在實際運用大數據量插入時100萬條數據的插入至少要數分鐘,如果使用load方法只需要十幾秒 

 

二、主鍵優化

  2.1 數據組織方式

    在InnoDB儲存引擎中,表數據都是根據主鍵順序組織存放的,這種存儲方式的表稱為索引組織表(index organized table)IOT

    

    說明1:在索引的B+數中所有的數據保存在葉子節點上,非葉子節點只保存主鍵key的值

    說明2:索引中的各個節點都是保存在邏輯結構頁上面的,一頁預設大小16K

 

  2.2 頁分裂

    頁可以為空,也可以填充一半,也可以填充100%,每個頁包含了2至N行數據,根據主鍵排列

    情況1:主鍵順序插入

    

 

    說明1:row是行數據,每一頁上可以存放多個行數據。    

    

    情況2:主鍵亂序插入

    

     說明1:當我們想要在插入一個id=50的數據時,會發生頁分裂

    

    說明2:這時會將 1#page 頁裡面的數據超過 50% 的數據,移動到新開闢的 3#page 頁中

    說明3:然後將 id=50 的數據也拼接到 3#page 頁中

    說明4:這時就會出現一個問題,3#page 中的索引比 2#page 頁中的索引小,所以還需要將 3#page 頁前置,這就叫頁分裂

    

  2.3 頁合併

    當刪除一行記錄時,實際上記錄並沒有被物理刪除,只是記錄被標記(flaged)為刪除並且它的空間變得允許被其他記錄聲明使用

    當頁中刪除的記錄達到 merge_threshold (預設為頁的50%),InnoDB 會開始尋找最靠近的頁(前或者後)看看是否可以合併以優化空間使用 

    

    說明1:這時在 2#page 刪除了13,14,15,16數據後,該頁空餘空間超過50%時就會尋找前一頁或者後一頁,是否同樣有不滿足50%,可以合併的

    

     說明2:這時 1#page 頁是滿的,不能合併,3#page 頁不滿可以合併,所以 3#page 頁遷移到 2#page 頁中

    

     說明3:這時如果在有數據20插入就可以直接插入到3#page頁上了,這就是頁合併。

 

  2.4 主鍵設計原則

    • 滿足業務需求的情況下,儘量減低主鍵的長度。
    • 插入數據時,儘量選擇順序插入,選擇使用auto_incerment自增主鍵,
    • 儘量不要用uuid作主鍵或者其他自然主鍵如身份證號,因為這個值是無需的,會存在頁分裂情況。

 

三、order by優化

  3.1 Using filesort

    通過表的索引或者全表掃描,讀取滿足條件的數據行,然後在排序緩衝區sort buffer 中完成排序操作,所有不是通過索引直接返回排序結果的排序都叫FileSort排序

  3.2 Using index

    通過有序索引順序掃描直接返回有序數據,這種情況即為using index,不需要額外的排序,操作效率高,即排序的列表欄位符合覆蓋索引

  3.3 案例

    emp表結構:

mysql> desc emp;
+-----------+-------------+------+-----+---------+----------------+
| Field     | Type        | Null | Key | Default | Extra          |
+-----------+-------------+------+-----+---------+----------------+
| id        | int         | NO   | PRI | NULL    | auto_increment |
| name      | varchar(20) | YES  |     | NULL    |                |
| age       | int         | YES  |     | NULL    |                |
| job       | varchar(20) | YES  |     | NULL    |                |
| salary    | int         | YES  |     | NULL    |                |
| entrydate | date        | YES  |     | NULL    |                |
| managerid | int         | YES  |     | NULL    |                |
| dept_id   | int         | YES  | MUL | NULL    |                |
+-----------+-------------+------+-----+---------+----------------+
8 rows in set (0.01 sec)

    emp表中索引情況

mysql> show index from emp;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| emp   |          0 | PRIMARY  |            1 | id          | A         |           7 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | fk_dept  |            1 | dept_id     | A         |           3 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+

    

    案例1:對查詢結果進行按 salary 和 age 都進行升序排序

mysql> explain select salary,age from emp order by salary, age;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra          |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
|  1 | SIMPLE      | emp   | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    7 |   100.00 | Using filesort |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+
1 row in set, 1 warning (0.00 sec)

    說明1:Extra 中值為 Using filesort 說明是先查出來需要的數據,然後再排序的,效率不高。

    說明2:為什麼會出現Using filesort呢?因為查詢的這些欄位在查詢之前是無須的,索引需要先將數據查詢出來,然後再做排序,這樣才能得到想要的排序好的數據。

   

    案例2:給 salary 和 age 添加一個聯合排序

mysql> create index salary_age_idx on emp(salary,age);
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show index from emp;
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name       | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| emp   |          0 | PRIMARY        |            1 | id          | A         |           7 |     NULL |   NULL |      | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | fk_dept        |            1 | dept_id     | A         |           3 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | salary_age_idx |            1 | salary      | A         |           7 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
| emp   |          1 | salary_age_idx |            2 | age         | A         |           7 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | NULL       |
+-------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
4 rows in set (0.00 sec)

    說明1:聯合索引 salary_age_idx 中 salary 是第一索引欄位,age 是第二索引欄位

    說明2:Collation 中A 代表升序,D 代表降序    

 

    案例3:再次使用 order by 對 salary 和 age 進行升序排序

mysql> explain select salary,age from emp order by salary,age;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | index | NULL          | salary_age_idx | 10      | NULL |    7 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select salary,age from emp order by salary;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | emp   | NULL       | index | NULL          | salary_age_idx | 10      | NULL |    7 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

    說明1:在做升序排列時,無論 order by 後面是組合索引的全部欄位,還是只有部分欄位,這時 Extra 的值都是Usind index,所以其查詢的結果直接就是排序好的結果

    說明2:為什麼呢?因為這個時候 salary和age是一個聯合索引,索引在文件中是一個帶順序的b+數結構,所以將這個欄位建立一個聯合索引,就意味著使用索引查詢的時候,就已經是帶著順序的數據了,所以這個時候就不需要在將數據從新在排序了,這樣的查詢效率就會更高。

    

    案例4: order by 中的欄位順序和索引順序不一致的情況

mysql> explain select salary,age from emp order by age,  salary;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | emp   | NULL       | index | NULL          | salary_age_idx | 10      | NULL |    7 |   100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

    說明1:這個時候order by 是age在前,salary在後,和索引的順序不一致,仍然會觸發索引,使用Using index,但是也會使用Using filesort,所以推薦大家使用正確的索引順序的欄位來進行排序

 

    案例5:對salary和age做降序查詢

mysql> explain select salary,age from emp order by salary desc, age desc;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | emp   | NULL       | index | NULL          | salary_age_idx | 10      | NULL |    7 |   100.00 | Backward index scan; Using index |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select id,salary,age from emp order by salary desc;
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key            | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | emp   | NULL       | index | NULL          | salary_age_idx | 10      | NULL |    7 |   100.00 | Backward index scan; Using index |
+----+-------------+-------+------------+-------+---------------+----------------+---------+------+------+----------+----------------------------------+
1 row in set, 1 warning (0.00 sec)

    說明1:無論是對salary和age同時做降序還是對其中一個欄位做降序排列,都會出現 Backward index scan; Using index,其中 Backward index scan 是反向掃描索引

    說明2:這是因為索引中預設的順序是升序的,而做降序排列,就需要反向掃描索引了

    

    案例7:創建一個 salary 和 age 都是降序的索引

create index salary_age_desc_idx on emp(salary desc, age desc);
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

    查詢目前所有的索引

mysql> show index from emp;
+-------+------------+---------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+------------+
| Table | Non_unique | Key_name            	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # 簡介 ### 按鍵 按鍵是輸入設備,一般來說,按鍵在沒有按下的時候是高電平;當按鍵按下的時候,為低電平。 在***DE2-70 User Manual***中 > Each switch provides a high logic level (3.3 volts) when it is not ...
  • IntelliJ IDEA的遠程開發功能,可以將編譯和運行等消耗資源任務放在伺服器上執行,降低本地電腦負載,但是體驗上和之前的IDEA操作保持一致,破舊的老機器也能煥發青春 ...
  • # Unity UGUI的Outline(描邊)組件的介紹及使用 ## 1. 什麼是Outline(描邊)組件? Outline(描邊)組件是Unity UGUI中的一種特效組件,用於給UI元素添加描邊效果。通過設置描邊的顏色、寬度和模糊程度,可以使UI元素在視覺上更加突出。 ## 2. Outli ...
  • # rsync教程、rsync+inotify實時同步 ## rsync介紹 英文全稱為Remote synchronization服務軟體 rsync是一個linux應用程式,可以實現**全量**以及**增量**的**本地**或者是**遠程**的**數據同步(拷貝)備份** 使用快速增量備份工具` ...
  • 一、問題描述: 在待機或正常使用過程中,時不時遇到桌面無響應的情況,但滑鼠正常移動。網路上大致給出以下幾種處理思路: 1.移除拓展塢,集線器2.打開設備管理器,通用串列匯流排控制器,對裡面每個設備的:“允許電腦關閉此設備以節約電源”,把勾去除3.通過命令徹底卸載小組件4.更換無線網卡驅動 本問題實際 ...
  • 博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ...
  • # 痞子衡嵌入式半月刊: 第 79 期 ![](https://raw.githubusercontent.com/JayHeng/pzh-mcu-bi-weekly/master/pics/pzh_mcu_bi_weekly.PNG) 這裡分享嵌入式領域有用有趣的項目/工具以及一些熱點新聞,農曆年 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家介紹的是**恩智浦i.MX RT1170 FlexSPI NAND啟動時間**。 本篇是 i.MXRT1170 啟動時間評測第四彈,前三篇分別給大家評測了 [Raw NAND 啟動時間](https://www.cnblogs.com/henj ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...