成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

執行Update語句,用沒用到索引,區別大嗎?

運維 數據庫運維
我們都知道,當執行 select 查詢語句時,用沒用到索引區別是很大的,若沒用到索引,一條 select 語句可能執行好幾秒或更久,若使用到索引則可能瞬間完成。

[[421146]]

本文轉載自微信公眾號「MySQL技術」,作者MySQL技術 。轉載本文請聯系MySQL技術公眾號。

前言

我們都知道,當執行 select 查詢語句時,用沒用到索引區別是很大的,若沒用到索引,一條 select 語句可能執行好幾秒或更久,若使用到索引則可能瞬間完成。那么當執行 update 語句時,用沒用到索引有什么區別呢,執行時間相差大嗎?本篇文章我們一起來探究下。

1. update SQL 測試

為了對比出差距,這里筆者創建兩張一樣數據的大表,一張有普通索引,一張無普通索引,我們來對比下二者的差別。

  1. # tb_noidx 表無普通索引 
  2. mysql> show create table tb_noidx\G 
  3. *************************** 1. row *************************** 
  4.        Table: tb_noidx 
  5. Create TableCREATE TABLE `tb_noidx` ( 
  6.   `increment_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵'
  7.   `col1` char(32) NOT NULL COMMENT '字段1'
  8.   `col2` char(32) NOT NULL COMMENT '字段2'
  9.   ... 
  10.   `del` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除'
  11. ) ENGINE=InnoDB AUTO_INCREMENT=3696887 DEFAULT CHARSET=utf8 COMMENT='無索引表' 
  12.  
  13. mysql> select count(*) from tb_noidx; 
  14. +----------+ 
  15. count(*) | 
  16. +----------+ 
  17. |  3590105 | 
  18. +----------+ 
  19.  
  20. mysql> select concat(round(sum(data_length/1024/1024),2),'MB'as data_length_MB, concat(round(sum(index_length/1024/1024),2),'MB'as index_length_MB 
  21.     -> from information_schema.tables where table_schema='testdb' and table_name = 'tb_noidx';  
  22. +----------------+-----------------+ 
  23. | data_length_MB | index_length_MB | 
  24. +----------------+-----------------+ 
  25. | 841.98MB       | 0.00MB          | 
  26. +----------------+-----------------+ 
  27.  
  28. # tb_withidx 表有普通索引 
  29. mysql> show create table tb_withidx\G 
  30. *************************** 1. row *************************** 
  31.        Table: tb_withidx 
  32. Create TableCREATE TABLE `tb_withidx` ( 
  33.   `increment_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主鍵'
  34.   `col1` char(32) NOT NULL COMMENT '字段1'
  35.   `col2` char(32) NOT NULL COMMENT '字段2'
  36.   ... 
  37.   `del` tinyint(4) NOT NULL DEFAULT '0' COMMENT '是否刪除'
  38.   PRIMARY KEY (`increment_id`), 
  39.   KEY `idx_col1` (`col1`), 
  40.   KEY `idx_del` (`del`) 
  41. ) ENGINE=InnoDB AUTO_INCREMENT=3696887 DEFAULT CHARSET=utf8 COMMENT='有索引表' 
  42.  
  43. mysql> select count(*) from tb_withidx; 
  44. +----------+ 
  45. count(*) | 
  46. +----------+ 
  47. |  3590105 | 
  48. +----------+ 
  49.  
  50. mysql> select concat(round(sum(data_length/1024/1024),2),'MB'as data_length_MB, concat(round(sum(index_length/1024/1024),2),'MB'as index_length_MB 
  51.     -> from information_schema.tables where table_schema='testdb' and table_name = 'tb_withidx';  
  52. +----------------+-----------------+ 
  53. | data_length_MB | index_length_MB | 
  54. +----------------+-----------------+ 
  55. | 841.98MB       | 210.50MB        | 
  56. +----------------+-----------------+ 

這里說明下,tb_noidx 和 tb_withidx 兩張表數據完全相同,表大概有 360W 條數據,約占用 840M 空間。其中 col1 字段區分度較高,del 字段區分度很低,下面我們分別以這兩個字段為篩選條件來執行 update 語句:

  1. # 以 col1 字段為篩選條件 來更新 col2 字段 
  2. mysql> explain update tb_withidx set col2 = '48348a10d7794d269ecf10f9e3f20b52' where col1 = '48348a10d7794d269ecf10f9e3f20b52'
  3. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+ 
  4. | id | select_type | table      | partitions | type  | possible_keys | key      | key_len | ref   | rows | filtered | Extra       | 
  5. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+ 
  6. |  1 | UPDATE      | tb_withidx | NULL       | range | idx_col1      | idx_col1 | 96      | const |    1 |   100.00 | Using where | 
  7. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+-------------+ 
  8. 1 row in set (0.00 sec) 
  9.  
  10. mysql> update tb_withidx set col2 = '48348a10d7794d269ecf10f9e3f20b52' where col1 = '48348a10d7794d269ecf10f9e3f20b52'
  11. Query OK, 1 row affected (0.01 sec) 
  12. Rows matched: 1  Changed: 1  Warnings: 0 
  13.  
  14. mysql> explain update tb_noidx set col2 = '48348a10d7794d269ecf10f9e3f20b52' where col1 = '48348a10d7794d269ecf10f9e3f20b52'
  15. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  16. | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  17. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  18. |  1 | UPDATE      | tb_noidx | NULL       | index | NULL          | PRIMARY | 4       | NULL | 3557131 |   100.00 | Using where | 
  19. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  20. 1 row in set (0.00 sec) 
  21.  
  22. mysql> update tb_noidx set col2 = '48348a10d7794d269ecf10f9e3f20b52' where col1 = '48348a10d7794d269ecf10f9e3f20b52'
  23. Query OK, 1 row affected (13.29 sec) 
  24. Rows matched: 1  Changed: 1  Warnings: 0 
  25.  
  26. # 以 col1 字段為篩選條件 來更新 col1 字段 
  27. mysql> explain update tb_withidx set col1 = 'col1aac4c0f07449c688af42886465b76b' where col1 = '95aac4c0f07449c688af42886465b76b'
  28. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+------------------------------+ 
  29. | id | select_type | table      | partitions | type  | possible_keys | key      | key_len | ref   | rows | filtered | Extra                        | 
  30. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+------------------------------+ 
  31. |  1 | UPDATE      | tb_withidx | NULL       | range | idx_col1      | idx_col1 | 96      | const |    1 |   100.00 | Using where; Using temporary | 
  32. +----+-------------+------------+------------+-------+---------------+----------+---------+-------+------+----------+------------------------------+ 
  33. 1 row in set (0.01 sec) 
  34.  
  35. mysql> update tb_withidx set col1 = 'col1aac4c0f07449c688af42886465b76b' where col1 = '95aac4c0f07449c688af42886465b76b'
  36. Query OK, 1 row affected, 1 warning (0.01 sec) 
  37. Rows matched: 1  Changed: 1  Warnings: 0 
  38.  
  39. mysql> explain update tb_noidx set col1 = 'col1aac4c0f07449c688af42886465b76b' where col1 = '95aac4c0f07449c688af42886465b76b'
  40. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  41. | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  42. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  43. |  1 | UPDATE      | tb_noidx | NULL       | index | NULL          | PRIMARY | 4       | NULL | 3557131 |   100.00 | Using where | 
  44. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  45. 1 row in set (0.01 sec) 
  46.  
  47. mysql> update tb_noidx set col1 = 'col1aac4c0f07449c688af42886465b76b' where col1 = '95aac4c0f07449c688af42886465b76b'
  48. Query OK, 1 row affected, 1 warning (13.15 sec) 
  49. Rows matched: 1  Changed: 1  Warnings: 0 
  50.  
  51. # 以 del 字段為篩選條件 來更新 col2 字段 
  52. # del為0的大概203W條 del為1的大概155W條 
  53. mysql> select del,count(*) from tb_withidx GROUP BY del; 
  54. +-----+----------+ 
  55. | del | count(*) | 
  56. +-----+----------+ 
  57. | 0   |  2033080 | 
  58. | 1   |  1557025 | 
  59. +-----+----------+ 
  60.  
  61. mysql> explain update tb_withidx set col2 = 'col24c0f07449c68af42886465b76' where del = 0; 
  62. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  63. | id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  64. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  65. |  1 | UPDATE      | tb_withidx | NULL       | index | idx_del       | PRIMARY | 4       | NULL | 3436842 |   100.00 | Using where | 
  66. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  67. 1 row in set (0.00 sec) 
  68.  
  69. mysql> update tb_withidx set col2 = 'col24c0f07449c68af42886465b76' where del = 0; 
  70. Query OK, 2033080 rows affected (47.15 sec) 
  71. Rows matched: 2033080  Changed: 2033080  Warnings: 0 
  72.  
  73. mysql> explain update tb_noidx set col2 = 'col24c0f07449c68af42886465b76' where del = 0; 
  74. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  75. | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  76. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  77. |  1 | UPDATE      | tb_noidx | NULL       | index | NULL          | PRIMARY | 4       | NULL | 3296548 |   100.00 | Using where | 
  78. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  79. 1 row in set (0.00 sec) 
  80.  
  81. mysql> update tb_noidx set col2 = 'col24c0f07449c68af42886465b76' where del = 0; 
  82. Query OK, 2033080 rows affected (49.79 sec) 
  83. Rows matched: 2033080  Changed: 2033080  Warnings: 0 
  84.  
  85. # 以 del 字段為篩選條件 來更新 del 字段 
  86. mysql> explain update tb_withidx set del = 2 where del = 0;                                       
  87. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  88. | id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  89. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  90. |  1 | UPDATE      | tb_withidx | NULL       | index | idx_del       | PRIMARY | 4       | NULL | 3436842 |   100.00 | Using where | 
  91. +----+-------------+------------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  92. 1 row in set (0.03 sec) 
  93.  
  94. mysql> update tb_withidx set del = 2 where del = 0; 
  95. Query OK, 2033080 rows affected (2 min 34.96 sec) 
  96. Rows matched: 2033080  Changed: 2033080  Warnings: 0 
  97.  
  98. mysql> explain update tb_noidx set del = 2 where del = 0;   
  99. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  100. | id | select_type | table    | partitions | type  | possible_keys | key     | key_len | ref  | rows    | filtered | Extra       | 
  101. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  102. |  1 | UPDATE      | tb_noidx | NULL       | index | NULL          | PRIMARY | 4       | NULL | 3296548 |   100.00 | Using where | 
  103. +----+-------------+----------+------------+-------+---------------+---------+---------+------+---------+----------+-------------+ 
  104. 1 row in set (0.00 sec) 
  105.  
  106. mysql>  update tb_noidx set del = 2 where del = 0;  
  107. Query OK, 2033080 rows affected (50.57 sec) 
  108. Rows matched: 2033080  Changed: 2033080  Warnings: 0 

從以上實驗大致可以看出,是否用到索引,對于 update 語句執行速度影響還是很大的,具體表現如下:

  • 若在區分度較高的字段上添加索引,并以該字段為篩選條件進行更新,則無論是更新該字段還是其他字段,用到索引的更新都要快好多。
  • 若在區分度很低的字段上添加索引,并以該字段為篩選條件進行更新,當更新其他字段時,有無索引區別不大,當更新這個區分度很低的字段時,用到索引的更新反而更慢。

2.一些經驗總結

我們試著來解釋下以上實驗結果,首先來看下 update SQL 執行流程,大致如下:

  • 首先客戶端發送請求到服務端,建立連接。
  • 服務端先看下查詢緩存,對于更新某張表的 SQL ,該表的所有查詢緩存都失效。
  • 接著來到解析器,進行語法分析,一些系統關鍵字校驗,校驗語法是否合規。
  • 然后優化器進行 SQL 優化,比如怎么選擇索引之類,然后生成執行計劃。
  • 執行器去存儲引擎查詢需要更新的數據。
  • 存儲引擎判斷當前緩沖池中是否存在需要更新的數據,存在就直接返回,否則去從磁盤加載數據。
  • 執行器調用存儲引擎 API 去更新數據。
  • 存儲器更新數據,同時寫入 undo log 、redo log 信息。
  • 執行器寫 binlog ,提交事務,流程結束。

也就是說,執行更新語句首先需要將被更新的記錄查詢出來,這也就不難理解為啥以區分度較高的字段為篩選條件進行更新,有索引的情況下執行更快。

對于區分度很低的字段,用沒用到索引則區別不大,原因是查詢出將被更新的記錄所需時間差別不大,需要掃描的行數差別不大。當更新區分度很低的字段的字段時,因為要維護索引 b+ 樹,所以會拖慢更新速度。

之前也有講過,雖然索引能加速查詢,但索引也是有缺點的,那就是索引需要動態的維護,當對表中的數據進行增加、刪除、修改時,會降低數據的維護速度。本次實驗結果也能論證這個結論。

通過本次實驗,我們也能得到一些索引相關經驗: 

  • 只為用于搜索、排序、分組、連接的列創建索引。
  • 索引盡量建在區分度高的字段上,避免在區分度低的字段上建索引。
  • 對經常更新的表避免創建過多的索引。
  • 不要有冗余索引,會增加維護成本。

 

責任編輯:武曉燕 來源: MySQL技術
相關推薦

2024-07-08 06:30:00

2025-02-28 01:00:00

2011-07-21 13:44:52

MySQLmysqldumpsl

2024-05-27 00:02:00

UpdateWhere索引

2024-08-19 12:30:29

Zustand前端

2024-08-19 08:48:49

代碼渲染組件

2010-11-11 11:13:54

SQL Server

2021-11-09 06:42:51

MySQLupdate語句

2010-05-25 15:24:38

MySQL updat

2021-05-26 05:22:48

SQL 數據庫SELECT

2010-09-27 10:29:14

sql update語

2010-10-08 16:01:17

mysql UPDAT

2011-04-22 14:45:45

SQL索引

2021-06-28 07:13:35

SQL語句索引

2021-12-17 00:10:00

ChromeDevtools功能

2010-06-11 17:36:46

MySQL語句

2021-02-18 09:44:52

MySQL

2021-03-04 09:50:23

MySQL查詢語句

2010-09-27 10:04:30

Sql Update語

2010-09-17 10:39:36

SQL中
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 九九热免费观看 | 国产综合网址 | 亚洲精品亚洲人成人网 | 在线小视频 | 国产日韩一区二区三免费 | 精品一区二区视频 | av片免费观看| 久久国产视频网站 | 中文字幕日韩欧美一区二区三区 | 2018国产大陆天天弄 | 毛片免费观看 | 亚洲性爰 | 2一3sex性hd| 精品一区二区三区91 | 一级免费毛片 | 不卡一二三区 | 一区二区视频在线 | 欧美午夜一区 | 国产精品免费一区二区三区四区 | 日日av| 成人免费大片黄在线播放 | 日日操日日干 | 黄色av免费 | 成年人在线视频 | 成人做爰www免费看视频网站 | 久久久久亚洲精品国产 | 亚洲综合色视频在线观看 | 日韩欧美网 | 99精品免费久久久久久久久日本 | 久热久热 | 国产精品日韩一区二区 | 国产不卡在线观看 | 看av电影| 成人午夜影院 | 羞视频在线观看 | 一级爱爱片 | 中文字幕亚洲欧美 | 色婷婷综合成人av | 国产精品亚洲一区二区三区在线 | 久久精品国产99国产 | 久久久久久综合 |