警惕 InnoDB 和 MyISAM 創建 Hash 索引陷阱


MySql 最經常使用存儲引擎 InnoDB 和 MyISAM 都不支持 Hash 索引,它們默認的索引都是 B-Tree。可是假設你在創建索引的時候定義其類型為 Hash,MySql 並不會報錯,並且你通過 SHOW CREATE TABLE 查看該索引也是 Hash,僅僅只是該索引實際上還是 B-Tree。


比方表 data_dict 的 DDL:

CREATE TABLE `data_dict` (
  `data_type` varchar(32) NOT NULL COMMENT '數據字典類型',
  `data_code` tinyint(4) NOT NULL COMMENT '數據字典代碼',
  `data_name` varchar(64) NOT NULL COMMENT '數據字典值',
  PRIMARY KEY (`data_type`,`data_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='數據字典表';

我們為 data_name 字段建立 Hash 索引:
ALTER TABLE data_dict ADD INDEX data_dict_dn USING HASH (data_name);

打印結果:
受影響的行: 0
時間: 0.345s

然后查看建表 DDL:
SHOW CREATE TABLE data_dict;

打印結果:
CREATE TABLE `data_dict` (
  `data_type` varchar(32) NOT NULL COMMENT '數據字典類型',
  `data_code` tinyint(4) NOT NULL COMMENT '數據字典代碼',
  `data_name` varchar(64) NOT NULL COMMENT '數據字典值',
  PRIMARY KEY (`data_type`,`data_code`),
  KEY `data_dict_dn` (`data_name`) USING HASH
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='數據字典表'

是 Hash,所以我們以為創建 Hash 索引成功。
其實並不是如此,我們都被 MySql 給騙了,我們使用 SHOW INDEXES FROM 語句對該表索引進行檢索:
SHOW INDEXES FROM data_dict;

打印結果:
我們使用 SHOW INDEXES FROM 語句對該表索引進行檢索
打回原形了。只是也不要失望,盡管常見存儲引擎並不支持 Hash 索引,但 InnoDB 有還有一種實現方法:自適應哈希索引。InnoDB 存儲引擎會監控對表上索引的查找。假設觀察到建立哈希索引能夠帶來速度的提升,則建立哈希索引。
我們能夠通過 SHOW ENGINE INNODB STATUS 來查看當前自適應哈希索引的使用狀況:
=====================================
2015-07-07 10:51:19 1d68 INNODB MONITOR OUTPUT
=====================================
Per second averages calculated from the last 36 seconds
......
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 2633, seg size 2635, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 348731, node heap has 2 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
......

從中我們能夠看到自適應哈希索引的相關信息:有使用大小、使用情況、每秒使用自適應哈希索引搜索的情況等。


MySql 各種存儲引擎的特性對照詳單:
MySql 各種存儲引擎的特性對照詳單
從中我們能夠看出,

  • InnoDB 支持事務。支持行級別鎖定。支持 B-tree、Full-text 等索引。不支持 Hash 索引。
  • MyISAM 不支持事務,支持表級別鎖定,支持 B-tree、Full-text 等索引。不支持 Hash 索引;
  • Memory 不支持事務,支持表級別鎖定。支持 B-tree、Hash 等索引,不支持 Full-text 索引。
  • NDB 支持事務,支持行級別鎖定。支持 Hash 索引。不支持 B-tree、Full-text 等索引;
  • Archive 不支持事務。支持表級別鎖定,不支持 B-tree、Hash、Full-text 等索引。
能夠使用 SHOW ENGINES 語句查看你的 MySql Server 所支持的存儲引擎,比方筆者用於本機測試的 5.6.25-log Win 版的查看結果例如以下:
支持的存儲引擎

從中能夠看出。InnoDB 是該版本號 MySql 的默認存儲引擎。也僅僅有 InnoDB 能夠支持事務、行級別鎖定、外鍵。支持的 MEMORY 是基於哈希的,數據都存放於內存。適用於暫時表。沒有看到既支持事務又支持哈希索引的 NDB 的身影。

為印證默認的存儲引擎,我們創建一個測試表 data_dict_test。注意建表語句里未定義存儲引擎:

CREATE TABLE `data_dict_test` (
  `data_type` varchar(32) NOT NULL COMMENT '數據字典類型',
  `data_code` tinyint(4) NOT NULL COMMENT '數據字典代碼',
  `data_name` varchar(64) NOT NULL COMMENT '數據字典值',
  PRIMARY KEY (`data_type`,`data_code`)
) DEFAULT CHARSET=utf8 COMMENT='數據字典表';
打印結果:

[SQL] CREATE TABLE `data_dict_test` (
  `data_type` varchar(32) NOT NULL COMMENT '數據字典類型',
  `data_code` tinyint(4) NOT NULL COMMENT '數據字典代碼',
  `data_name` varchar(64) NOT NULL COMMENT '數據字典值',
  PRIMARY KEY (`data_type`,`data_code`)
) DEFAULT CHARSET=utf8 COMMENT='數據字典表';
受影響的行: 0
時間: 0.262s

然后查看建表 DDL:

SHOW CREATE TABLE data_dict_test;
打印結果:

CREATE TABLE `data_dict_test` (
  `data_type` varchar(32) NOT NULL COMMENT '數據字典類型',
  `data_code` tinyint(4) NOT NULL COMMENT '數據字典代碼',
  `data_name` varchar(64) NOT NULL COMMENT '數據字典值',
  PRIMARY KEY (`data_type`,`data_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='數據字典表'

這次 SHOW CREATE TABLE 沒有欺騙我們,明白給出的就是 InnoDB,盡管我們建表時沒有指定。

筆者建議使用 SHOW TABLE STATUS 語句來查看特定表的存儲引擎:

SHOW TABLE STATUS WHERE NAME = 'data_dict_test';
打印結果:

SHOW TABLE STATUS WHERE NAME = 'data_dict_test'


參考資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM