91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

MySQL中InnoDB引擎如何對索引的擴展

發布時間:2021-10-08 16:42:48 來源:億速云 閱讀:100 作者:柒染 欄目:MySQL數據庫

MySQL中InnoDB引擎如何對索引的擴展,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

InnoDB引擎對索引的擴展,自動追加主鍵值及其對執行計劃的影響。


MySQL中,使用InnoDB引擎的每個表,創建的普通索引(即非主鍵索引),都會同時保存主鍵的值。
比如語句
CREATE TABLE t1 (
 i1 INT NOT NULL DEFAULT 0,
 i2 INT NOT NULL DEFAULT 0,
 d DATE DEFAULT NULL,
 PRIMARY KEY (i1, i2),
 INDEX k_d (d)
) ENGINE = InnoDB;
創建了t1表,其主鍵為(i1, i2),同時創建了基于d列的索引k_d,但其實在底層,InnoDB引擎將索引k_d擴展成(d,i1,i2)。
InnoDB引擎這么做,是用空間換性能,優化器在判斷是否使用索引及使用哪個索引時會有更多列參考,這樣可能生成更高效的執行計劃,獲得更好的性能。
優化器在ref、range和index_merge類型的訪問,Loose Index Scan訪問,連接和排序優化, MIN()/MAX()優化時使都會使用擴展列。
我們來看個例子:
root@database-one 15:15:  [gftest]> CREATE TABLE t1 (
   ->   i1 INT NOT NULL DEFAULT 0,
   ->   i2 INT NOT NULL DEFAULT 0,
   ->   d DATE DEFAULT NULL,
   ->   PRIMARY KEY (i1, i2),
   ->   INDEX k_d (d)
   -> ) ENGINE = InnoDB;
Query OK, 0 rows affected (0.06 sec)

root@database-one 15:15:  [gftest]> INSERT INTO t1 VALUES
   -> (1, 1, '1998-01-01'), (1, 2, '1999-01-01'),
   -> (1, 3, '2000-01-01'), (1, 4, '2001-01-01'),
   -> (1, 5, '2002-01-01'), (2, 1, '1998-01-01'),
   -> (2, 2, '1999-01-01'), (2, 3, '2000-01-01'),
   -> (2, 4, '2001-01-01'), (2, 5, '2002-01-01'),
   -> (3, 1, '1998-01-01'), (3, 2, '1999-01-01'),
   -> (3, 3, '2000-01-01'), (3, 4, '2001-01-01'),
   -> (3, 5, '2002-01-01'), (4, 1, '1998-01-01'),
   -> (4, 2, '1999-01-01'), (4, 3, '2000-01-01'),
   -> (4, 4, '2001-01-01'), (4, 5, '2002-01-01'),
   -> (5, 1, '1998-01-01'), (5, 2, '1999-01-01'),
   -> (5, 3, '2000-01-01'), (5, 4, '2001-01-01'),
   -> (5, 5, '2002-01-01');
Query OK, 25 rows affected (0.01 sec)
Records: 25  Duplicates: 0  Warnings: 0

root@database-one 15:21:  [gftest]> show index from t1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| t1    |          0 | PRIMARY  |            1 | i1          | A         |           5 |     NULL | NULL   |      | BTREE      |         |               |
| t1    |          0 | PRIMARY  |            2 | i2          | A         |          25 |     NULL | NULL   |      | BTREE      |         |               |
| t1    |          1 | k_d      |            1 | d           | A         |           5 |     NULL | NULL   | YES  | BTREE      |         |               |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.01 sec)
在普通索引中追加擴展主鍵是InnoDB在底層做的,show index等語句不顯示追加列,但我們可以通過其它方式來驗證。看這個SQL
SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = ‘2000-01-01’
如果InnoDB沒有擴展索引,索引k_d為(d),生成的執行計劃應該類似這樣,使用k_d索引找到d為’2000-01-01’的5行數據,再回表過濾出i1為3的,最后計算count。或者使用主鍵索引找到i1為3的5行數據,再回表過濾出d為’2000-01-01’的,最后計算count。下面僅示意走k_d索引的情況:
mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t1
        type: ref
possible_keys: PRIMARY,k_d
         key: k_d
     key_len: 4
         ref: const
        rows: 5
       Extra: Using where; Using index
如果InnoDB擴展了索引,索引k_d為(d,i1,i2),這時,優化器可以使用最左邊的索引前綴(d,i1),生成的執行計劃應該類似這樣,使用k_d索引找到d為’2000-01-01’及i1為3的1行數據,然后計算count
mysql> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t1
        type: ref
possible_keys: PRIMARY,k_d
         key: k_d
     key_len: 8
         ref: const,const
        rows: 1
       Extra: Using index
并且d列是DATE類型占4個字節,i1是INT類型占4個字節,所以查詢中使用的鍵值長度就是8個字節(key_len: 8)。
我們看看實際生成的執行計劃
root@database-one 15:35:  [gftest]> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t1
  partitions: NULL
        type: ref
possible_keys: PRIMARY,k_d
         key: k_d
     key_len: 8
         ref: const,const
        rows: 1
    filtered: 100.00
       Extra: Using index
1 row in set, 1 warning (0.01 sec)
果然跟我們的判斷一致,注意執行計劃中的細節:
  • key_len從4字節變為8字節,表明鍵查找使用列d和i1,而不僅僅是d。

  • ref從const更改為const,const,表明查找使用兩個鍵值,而不是一個。

  • rows從5減少到1,表明檢索更少的行。

  • Extra從Using where; Using index改為Using index,表示只用索引讀取,不必回表。


InnoDB引擎底層擴展普通索引的情況,也可以通過跟MyISAM引擎對比來進行旁證:
root@database-one 16:07:  [gftest]> CREATE TABLE t1MyISAM (
   ->   i1 INT NOT NULL DEFAULT 0,
   ->   i2 INT NOT NULL DEFAULT 0,
   ->   d DATE DEFAULT NULL,
   ->   PRIMARY KEY (i1, i2),
   ->   INDEX k_d (d)
   -> ) ENGINE = MyISAM;
Query OK, 0 rows affected (0.01 sec)

root@database-one 16:07:  [gftest]> INSERT INTO t1myisam VALUES
   -> (1, 1, '1998-01-01'), (1, 2, '1999-01-01'),
   -> (1, 3, '2000-01-01'), (1, 4, '2001-01-01'),
   -> (1, 5, '2002-01-01'), (2, 1, '1998-01-01'),
   -> (2, 2, '1999-01-01'), (2, 3, '2000-01-01'),
   -> (2, 4, '2001-01-01'), (2, 5, '2002-01-01'),
   -> (3, 1, '1998-01-01'), (3, 2, '1999-01-01'),
   -> (3, 3, '2000-01-01'), (3, 4, '2001-01-01'),
   -> (3, 5, '2002-01-01'), (4, 1, '1998-01-01'),
   -> (4, 2, '1999-01-01'), (4, 3, '2000-01-01'),
   -> (4, 4, '2001-01-01'), (4, 5, '2002-01-01'),
   -> (5, 1, '1998-01-01'), (5, 2, '1999-01-01'),
   -> (5, 3, '2000-01-01'), (5, 4, '2001-01-01'),
   -> (5, 5, '2002-01-01');
Query OK, 25 rows affected (0.02 sec)
Records: 25  Duplicates: 0  Warnings: 0

root@database-one 16:07:  [gftest]> EXPLAIN SELECT COUNT(*) FROM t1myisam WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t1myisam
  partitions: NULL
        type: ref
possible_keys: PRIMARY,k_d
         key: PRIMARY
     key_len: 4
         ref: const
        rows: 4
    filtered: 16.00
       Extra: Using where
1 row in set, 1 warning (0.01 sec)
可以看到,同樣的結構同樣的數據,因為MyISAM引擎不會在底層自動擴展普通索引,所以執行計劃還是通過主鍵索引進行處理。
按照官方手冊的說明,也可以用SHOW STATUS命令來驗證
root@database-one 16:12:  [gftest]> FLUSH TABLE t1;
Query OK, 0 rows affected (0.00 sec)

root@database-one 16:12:  [gftest]> FLUSH STATUS;
Query OK, 0 rows affected (0.14 sec)

root@database-one 16:12:  [gftest]> SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01';
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
1 row in set (0.03 sec)

root@database-one 16:12:  [gftest]> SHOW STATUS LIKE 'handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 1     |
| Handler_read_last     | 0     |
| Handler_read_next     | 1     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+
7 rows in set (0.01 sec)

root@database-one 16:13:  [gftest]> FLUSH TABLE t1myisam;
Query OK, 0 rows affected (0.01 sec)

root@database-one 16:13:  [gftest]> FLUSH STATUS;
Query OK, 0 rows affected (0.00 sec)

root@database-one 16:13:  [gftest]> SELECT COUNT(*) FROM t1myisam WHERE i1 = 3 AND d = '2000-01-01';
+----------+
| COUNT(*) |
+----------+
|        1 |
+----------+
1 row in set (0.01 sec)

root@database-one 16:13:  [gftest]> SHOW STATUS LIKE 'handler_read%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Handler_read_first    | 0     |
| Handler_read_key      | 1     |
| Handler_read_last     | 0     |
| Handler_read_next     | 5     |
| Handler_read_prev     | 0     |
| Handler_read_rnd      | 0     |
| Handler_read_rnd_next | 0     |
+-----------------------+-------+
7 rows in set (0.00 sec)
Handler_read_next表示在進行索引掃描時,按照索引從數據文件里取數據的次數。使用MyISAM引擎的t1myisam表,Handler_read_next值為5,使用InnoDB引擎的t1表,Handler_read_next值減小到1,就是因為InnoDB引擎對索引進行了主鍵擴展,讀取的次數少,效率更好。
默認情況下,優化器分析InnoDB表的索引時會考慮擴展列,但如果因為特殊原因讓優化器不考慮擴展列,可以使用SET optimizer_switch = 'use_index_extensions=off’設置。
root@database-one 16:26:  [gftest]> SET optimizer_switch = 'use_index_extensions=off';
Query OK, 0 rows affected (0.01 sec)

root@database-one 16:26:  [gftest]> EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
*************************** 1. row ***************************
          id: 1
 select_type: SIMPLE
       table: t1
  partitions: NULL
        type: ref
possible_keys: PRIMARY,k_d
         key: PRIMARY
     key_len: 4
         ref: const
        rows: 5
    filtered: 20.00
       Extra: Using where
1 row in set, 1 warning (0.02 sec)

看完上述內容,你們掌握MySQL中InnoDB引擎如何對索引的擴展的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

南郑县| 堆龙德庆县| 东乡县| 邓州市| 全南县| 滁州市| 平山县| 柳林县| 家居| 鲁甸县| 河南省| 阜城县| 定结县| 姜堰市| 塔城市| 新密市| 伽师县| 辽阳市| 临武县| 离岛区| 西乌珠穆沁旗| 抚松县| 登封市| 灌阳县| 新和县| 凤山市| 武安市| 隆化县| 东海县| 卢湾区| 伊春市| 浦东新区| 洛阳市| 五常市| 安福县| 农安县| 育儿| 高要市| 正蓝旗| 两当县| 九江县|