MySQL中索引和優化的用法總結


1、什么是數據庫中的索引?索引有什么作用?

  引入索引的目的是為了加快查詢速度。如果數據量很大,大的查詢要從硬盤加載數據到內存當中。

2、InnoDB中的索引原理是怎么樣的?

  InnoDB是Mysql的默認存儲引擎,InnoDB有兩種索引:B+樹索引和哈希索引,其中哈希索引是自適應性的,存儲引擎會根據表的使用情況,自動創建哈希索引,不能人為的干涉。

  B樹、B-樹、B+樹、B*樹四種數據結構在索引中的運用,這四種數據結構的順序必須是這樣的。分別闡述如下:

B樹:二叉樹,每個結點只存儲一個關鍵字,等於則命中,小於走左結點,大於走右結點;

B-樹:多路搜索樹,每個結點存儲M/2到M個關鍵字,非葉子結點存儲指向關鍵字范圍的子結點;所有關鍵字在整顆樹中出現,且只出現一次,非葉子結點可以命中;

B+樹:在B-樹基礎上,為葉子結點增加鏈表指針,所有關鍵字都在葉子結點中出現,非葉子結點作為葉子結點的索引;B+樹總是到葉子結點才命中;

B*樹:在B+樹基礎上,為非葉子結點也增加鏈表指針,將結點的最低利用率從1/2提高到2/3;

  首先,B樹也叫作二叉搜索樹,字如其義。B樹有如下三個特點:所有非葉子節點至多擁有兩個兒子;所有節點存儲一個關鍵字;非葉子節點的左指針指向小於其關鍵字的子樹,右指針指向大於其關鍵字的子樹。

  B樹的搜索,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那么就命中,否則,如果查詢關鍵字比結點關鍵字小,就進入左兒子;如果比結點關鍵字大,就進入右兒子;如果左兒子或右兒子的指針為空,則報告找不到相應的關鍵字。如果B樹的所有非葉子結點的左右子樹的結點數目均保持差不多(平衡),那么B樹的搜索性能逼近二分查找;但它比連續內存空間的二分查找的優點是,改變B樹結構(插入與刪除結點)不需要移動大段的內存數據,甚至通常是常數開銷。最右邊也是一個B樹,但它的搜索性能已經是線性的了;同樣的關鍵字集合有可能導致不同的樹結構索引;所以,使用B樹還要考慮盡可能讓B樹保持左圖的結構,和避免右圖的結構,也就是所謂的“平衡”問題;實際使用的B樹都是在原B樹的基礎上加上平衡算法,即“平衡二叉樹”;如何保持B樹結點分布均勻的平衡算法是平衡二叉樹的關鍵;平衡算法是一種在B樹中插入和刪除結點的策略;

  其次,B-樹。數據量越大,B樹的高度會越高,之所以會越高,主要是因為二叉引起的。所以在此基礎上我們定義了B-樹的規范如下:B-樹不是二叉的,所以又叫作多路搜索樹。

B-樹是一種多路搜索樹(並不是二叉的):

1.定義任意非葉子結點最多只有M個兒子;且M>2;
2.根結點的兒子數為[2, M];除根結點以外的非葉子結點的兒子數為[M/2, M];
3.每個結點存放至少M/2-1(取上整)和至多M-1個關鍵字;(至少2個關鍵字)
4.非葉子結點的關鍵字個數=指向兒子的指針個數-1;
5.非葉子結點的關鍵字:K[1], K[2], …, K[M-1];且K[i] < K[i+1];
6.非葉子結點的指針:P[1], P[2], …, P[M];其中P[1]指向關鍵字小於K[1]的子樹,P[M]指向關鍵字大於K[M-1]的子樹,其它P[i]指向關鍵字屬於(K[i-1], K[i])的子樹;
7.所有葉子結點位於同一層;如圖所示中(M=3)

B-樹的搜索,從根結點開始,對結點內的關鍵字(有序)序列進行二分查找,如果命中則結束,否則進入查詢關鍵字所屬范圍的兒子結點重復,直到所對應的兒子指針為空,或已經是葉子結點。

B-樹的特性:

       1.關鍵字集合分布在整顆樹中;

       2.任何一個關鍵字出現且只出現在一個結點中;

       3.搜索有可能在非葉子結點結束;

       4.其搜索性能等價於在關鍵字全集內做一次二分查找;

       5.自動層次控制;

       由於限制了除根結點以外的非葉子結點,至少含有M/2個兒子,確保了結點的至少利用率,其最底搜索性能如圖,
其中,M為設定的非葉子結點最多子樹個數,N為關鍵字總數;
所以B-樹的性能總是等價於二分查找(與M值無關),也就沒有B樹平衡的問題;由於M/2的限制,在插入結點時,如果結點已滿,需要將結點分裂為兩個各占M/2的結點;刪除結點時,需將兩個不足M/2的兄弟結點合並;

  其次,B+樹。B樹、B-樹、B+樹、B*樹。B樹是二叉搜索樹,B-樹、B+樹、B*樹都是多路搜索樹。B-樹定義了基本的規范,它有個特點,關鍵字出現在非葉子節點或者葉子節點,子樹的指針比關鍵字個數大一個。B+樹在這兩方面分別做了升級,定義如下:

 B+樹是B-樹的變體,也是一種多路搜索樹:

       1.其定義基本與B-樹同,除了:

       2.非葉子結點的子樹指針與關鍵字個數相同;

       3.非葉子結點的子樹指針P[i],指向關鍵字值屬於[K[i], K[i+1])的子樹

(B-樹是開區間);

       5.為所有葉子結點增加一個鏈指針;

       6.所有關鍵字都在葉子結點出現;


B+的搜索與B-樹也基本相同,區別是B+樹只有達到葉子結點才命中(B-樹可以在非葉子結點命中),其性能也等價於在關鍵字全集做一次二分查找;

B+的特性:

       1.所有關鍵字都出現在葉子結點的鏈表中(稠密索引),且鏈表中的關鍵字恰好是有序的;

       2.不可能在非葉子結點命中;

       3.非葉子結點相當於是葉子結點的索引(稀疏索引),葉子結點相當於是存儲(關鍵字)數據的數據層;

       4.更適合文件索引系統;

  最后B*樹,它是B+樹的變體,在B+樹的非根和非葉子結點再增加指向兄弟的指針。

 

B*樹定義了非葉子結點關鍵字個數至少為(2/3)*M,即塊的最低使用率為2/3(代替B+樹的1/2);

B+樹的分裂:當一個結點滿時,分配一個新的結點,並將原結點中1/2的數據復制到新結點,最后在父結點中增加新結點的指針;B+樹的分裂只影響原結點和父結點,而不會影響兄弟結點,所以它不需要指向兄弟的指針;

B*樹的分裂:當一個結點滿時,如果它的下一個兄弟結點未滿,那么將一部分數據移到兄弟結點中,再在原結點插入關鍵字,最后修改父結點中兄弟結點的關鍵字(因為兄弟結點的關鍵字范圍改變了);
如果兄弟也滿了,則在原結點與兄弟結點之間增加新結點,並各復制1/3的數據到新結點,最后在父結點增加新結點的指針; 所以,B*樹分配新結點的概率比B+樹要低,空間使用率更高;

3、如何在Navicat中對表添加索引?

#刪除表
DROP TABLE test.idc_work_order_main

# 創建表結構idc_work_order_main
CREATE TABLE `idc_work_order_main` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',
  `creator` varchar(128) NOT NULL DEFAULT '0' COMMENT '創建人',
  `gmt_create` timestamp NULL DEFAULT NULL COMMENT '創建時間',
  `modifier` varchar(128) DEFAULT '0' COMMENT '修改人',
  `gmt_modified` timestamp NULL DEFAULT NULL COMMENT '修改時間',
  `title` varchar(64) DEFAULT NULL COMMENT '工單標題',
  `category` varchar(32) DEFAULT NULL COMMENT '工單類別',
  `subject` varchar(32) DEFAULT NULL COMMENT '工單類型',
  `demander` varchar(30) DEFAULT NULL COMMENT '需求方',
  `is_atomic` char(1) DEFAULT 'y' COMMENT '是否原子工單',
  `atomic_id` int(11) DEFAULT NULL COMMENT '當前原子工單在列表中ID',
  `site` varchar(50) DEFAULT NULL COMMENT '工單所在機房',
  `operationer` varchar(32) DEFAULT NULL COMMENT '當前處理人',
  `operation_role` varchar(50) DEFAULT NULL COMMENT '當前處理角色',
  `state` varchar(50) DEFAULT NULL COMMENT '工單狀態',
  `sub_state` varchar(50) DEFAULT NULL COMMENT '工單子狀態',
  `expect_time` timestamp NULL DEFAULT NULL COMMENT '預期結單時間',
  `sla` bigint(20) DEFAULT NULL COMMENT 'sla',
  `evaluation` varchar(200) DEFAULT NULL COMMENT '評價',
  `create_source` varchar(32) DEFAULT 'TBOSS' COMMENT '創建源',
  `source_key` varchar(32) DEFAULT NULL COMMENT '創建源唯一標示',
  `is_deleted` char(1) DEFAULT 'n' COMMENT '是否已刪除y,n',
  `remark` varchar(500) DEFAULT NULL COMMENT '備注',
  `parent_id` int(11) DEFAULT '0' COMMENT '父工單ID',
  `asset_total` int(11) DEFAULT '0' COMMENT '設備總數',
  `sla_standard` double DEFAULT NULL COMMENT '標准時間',
  `sla_unit` char(1) DEFAULT NULL COMMENT 'sla 單位',
  `effective_date` timestamp NULL DEFAULT NULL COMMENT '提單時間(生效時間)',
  `is_timeout` char(1) DEFAULT 'n' COMMENT '是否超時,‘y’超時,‘n’未超時',
  `statement_date` timestamp NULL DEFAULT NULL COMMENT '結單的時間',
  `source_creator` varchar(32) DEFAULT NULL COMMENT '第三方創建人信息(域賬號)',
  `atomic_order_id` int(11) DEFAULT NULL COMMENT '當前原子工單編號',
  `order_device_type` varchar(50) DEFAULT 'SERVER' COMMENT '工單設備類型(server=服務器,network_serve等)',
  `finish_asset_total` int(11) DEFAULT '0' COMMENT '完成設備數',
  PRIMARY KEY (`id`),
  KEY `idx_statement_date` (`statement_date`),
  KEY `idx_parent_id` (`parent_id`),
  KEY `idx_gmt_modified` (`gmt_modified`),
  KEY `idx_gmt_create` (`gmt_create`)
) ENGINE=InnoDB AUTO_INCREMENT=182431 DEFAULT CHARSET=utf8 COMMENT='工單主表';

#顯示建表信息
SHOW CREATE TABLE idc_work_order_main

#添加索引
ALTER TABLE idc_work_order_main ADD INDEX atomic_order_id (atomic_order_id)
SHOW INDEX FROM idc_work_order_main
EXPLAIN SELECT * FROM idc_work_order_main WHERE atomic_order_id = '9956'

#添加主鍵 (唯一)
ALTER TABLE idc_work_order_main ADD PRIMARY KEY source_creator (source_creator)

#添加唯一索引
ALTER TABLE idc_work_order_main ADD UNIQUE source_creator (source_creator)
SHOW INDEX FROM idc_work_order_main

#添加聯合索引
ALTER TABLE idc_work_order_main ADD INDEX id_source_parent_create_atomic (id,source_creator,parent_id,gmt_create,atomic_order_id)
SHOW INDEX FROM idc_work_order_main

  關於索引:

1.一本書光目錄就占半本書,目錄(索引)還有意義嗎?索引過多一定情況下會導致索引文件過大(指數增長),系統在尋址時查詢時間增長。
2.性別字段就男女兩個,加索引純浪費。一個索引會在 update 或 insert 時增加一次 I/O,對於操作系統底層來說是非常損耗性能的。

3.首先mysql是B+樹索引,這種作為索引的好處是可以對有序的記錄作logN級的查找,不過對於沒有大小之分的數據來說,還是建立哈希索引更好,因為哈希索引的時間復雜度基本是log1的。(注意此處有序和無序的概念)。

4.索引的命名規則:表名_字段名,需要加索引的字段,要在where條件中,數據量少的字段不需要加索引,如果where條件中是OR關系,加索引不起作用,符合最左原則。

4、索引中的index和key的使用

  key 是數據庫的物理結構,處於模型層面的,它包含兩層意義和作用,一是約束(偏重於約束和規范數據庫的結構完整性),二是索引(輔助查詢用的)。包括primary key, unique key, foreign key 等。

primary key 有兩個作用,一是約束作用(constraint),用來規范一個存儲主鍵和唯一性,但同時也在此key上建立了一個index;
unique key 也有兩個作用,一是約束作用(constraint),規范數據的唯一性,但同時也在這個key上建立了一個index;
foreign key也有兩個作用,一是約束作用(constraint),規范數據的引用完整性,但同時也在這個key上建立了一個index;

可見,mysql的key是同時具有constraint和index的意義,這點和其他數據庫表現的可能有區別。index是數據庫的物理結構,處於實現層面的,它只是輔助查詢的,它創建時會在另外的表空間(mysql中的innodb表空間)以一個類似目錄的結構存儲。索引只是索引,它不會去約束索引的字段的行為(那是key要做的事情)。Mysql常見索引有:主鍵索引、唯一索引、普通索引、全文索引、組合索引。

參考:

1.http://www.data.5helpyou.com/article392.html

2.關於where條件中or對索引影響:http://blog.csdn.net/hguisu/article/details/7106159


免責聲明!

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



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