存储数据之外,数据库还维护了一个满足特定查找的数据结构,这些数据结构以某种方式指向数据,以某种算法去查询这个数据结构,目的就是提高查询效率。
一般我们平常所说的索引,如果可以特别指明,都是指B树结构组织的索引。而索引又分类为:次要索引、覆盖索引、复合索引、前缀索引、唯一索引。
索引优势:
索引劣势:
1.添加主键索引
ALTER TABLE table_name
ADD PRIMARY KEY (column
)
2.添加唯一索引
ALTER TABLE table_name
ADD UNIQUE (column
)
3.添加全文索引
ALTER TABLE table_name
ADD FULLTEXT (column
)
4.添加普通索引
ALTER TABLE table_name
ADD INDEX index_name (column
)
5.添加多列索引
ALTER TABLE table_name
ADD INDEX index_name (column1
, column2
, column3
)
DROP INDEX [indexName] ON tableName
SHOW INDEX FROM tableName
看上图中,一棵B+树,浅蓝色的块我们称之为一个磁盘块,可以看到每个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P1、P2、P3。
我如果要找29这个数字,那么从根找,P1表示小与17的,P2表示大于17小与35的,P3表示大于35的,那么往下走,真实的数据存在于叶子节点,也就是第三层,即3、5、9、10、13…依次往右看。假设我要查找非叶子节点(第二层),不存储真实的数据,只存储指引搜索方向的数据项,如17、35并不存在真实的数据表中,也就是相当于一个参考值。如果查找29,但是我们先给参考项,那么根据图示,29在17和35之间,锁定磁盘块1的P2指针,找到指针P2,内存时间非常短,相比磁盘的IO可以忽略不计,那么下来之后,找到磁盘块3,也就是不见得加载磁盘块2,这里就第二次IO了,那么看图,29在26和30之间,那么又指向指针P2,再往下就加载到了磁盘块8的内存,发生第三次IO,同时内存中做二分查找找到29,结束查询,总共三次IO。
看Btree也就是三层楼那么高,也就是尽量把数据横向扩,高度矮比较好,真实的情况是,3层的B+树 可以表示上百万的数据,如果上百万的数据查找只需三次IO,性能提高将是巨大的,如果没有所用,每个数据项都要发生一次IO,那么总共需要上百万次的IO,显然成本非常高。
下面引入一个概念,sql 优化几个概念要明白。
某个列唯一键的数量叫作基数。比如性别列,该列只有男女之分,所以这一列基数是2。主键列的基数等于表的总行数。基数的高低影响列的数据分布。使用如下 sql 查看表中数据分布(摘抄自《SQL优化核心思想》)
select count(distinct owner),count(distinct object_id),count(*) from test;
TEST 表的总行数为72462,而上面sql去重后行数为 29,那么基数就是 29,说明owner列里面有大量重复值。
这先要从InnoDB的索引实现说起,InnoDB有两大类索引:
InnoDB聚集索引的叶子节点存储行记录,因此, InnoDB必须要有,且只有一个聚集索引,
(1)如果表定义了PK,则PK就是聚集索引;
(2)如果表没有定义PK,则第一个not NULL unique列是聚集索引;
(3)否则,InnoDB会创建一个隐藏的row-id作为聚集索引
所以PK查询非常快,直接定位行记录
就是我们平时使用 create index… 创建的,这个索引只存储对应叶子节点存储主键值。
假设创建表
t(id PK, name, sex, flag, index(name)));
id是聚集索引,name是普通索引。
当使用 Select * from table where name = ‘xx’ 时候,会有以下步骤:
上面需要扫描2次索引树,这就是所谓的回表查询,先定位主键值,再定位行记录,它的性能较扫一遍索引树更低。所以有些人认为过滤条件使用了索引,SQL优化的不错,这其实是一种错误的认识,使用了索引并不代表查询就最优,可能会造成回表太多造成 IO 贼高。所以在数据
如果要想避免回表,建议使用覆盖索引,将被查询的字段,建立到联合索引里去。