《SUO YIN》 --- ZXQ is a fool !

啥是索引

索引其实是一种数据结构,能够帮助我们快速的检索数据库中的数据。
索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。

索引常见模型

举3个 : hash表 、 有序集合 、

哈希表是一种以key-value存储数据的结构
利: 等值查询
弊: 范围查询 没有任何顺序关系 -> 全表扫描

问: hash碰撞是咋整的?
先问问小泉
$this->狗亮亮曾经分享给我的拉链法

typedef struct _hashtable { 
    uint nTableSize;        // hash Bucket的大小,最小为8,以2x增长。
    uint nTableMask;        // nTableSize-1 , 索引取值的优化
    uint nNumOfElements;    // hash Bucket中当前存在的元素个数,count()函数会直接返回此值 
    ulong nNextFreeElement; // 下一个数字索引的位置
    Bucket *pInternalPointer;   // 当前遍历的指针(foreach比for快的原因之一)
    Bucket *pListHead;          // 存储数组头元素指针
    Bucket *pListTail;          // 存储数组尾元素指针
    Bucket **arBuckets;         // 存储hash数组
    dtor_func_t pDestructor;    // 在删除元素时执行的回调函数,用于资源的释放
    zend_bool persistent;       //指出了Bucket内存分配的方式。如果persisient为TRUE,则使用操作系统本身的内存分配函数为Bucket分配内存,否则使用PHP的内存分配函数。
    unsigned char nApplyCount; // 标记当前hash Bucket被递归访问的次数(防止多次递归)
    zend_bool bApplyProtection;// 标记当前hash桶允许不允许多次访问,不允许时,最多只能递归3次
#if ZEND_DEBUG
    int inconsistent;
#endif
} HashTable;

有序集合
利: 等值查询、范围查询(2分法) 都挺好
弊: 适用静态存储引擎. 更新数据,维护结构成本高

多路平衡查询树 节点是天然有序的 左子<父<右子

InnoDB中:
一个索引对应一颗B+
那么..........叶节点 可以存储what?
1)整行数据 -> 主键索引 聚簇索引
2)主键值 -> 非主键索引 二级索引 非聚簇索引

聚簇索引和非聚簇索引,在查询数据的时候有区别吗?
mysql> create table T(
id int primary key, 
k int not null, 
name varchar(16),
index (k))engine=InnoDB;

select * from T where id=500
select * from T where k=5
select id from T where k=5

image.png

索引维护:

维持多路平衡 维持索引的有序性
上边, 新增一个id: 700 在R5 后继续新增就行了 . 如果插入一个ID:400的 就很烦了
更闹心的是页分裂, 如果R5所在的数据页满了,这时候根据B+树算法,就需要再申请一个数据页,然后挪部分数据过去 这又造成了数据页的利用率问题 当两个相邻数据页有数据删除 利用率很低时,会产生页分裂的逆过程 页的合并

绝大情况 :NOT NULL PRIMARY KEY AUTO_INCREMENT。 (只有一个索引 且是唯一索引)
新增记录 追加操作 避免页分裂

从性能和存储空间方面考量,自增主键往往是更合理的选择。

身份证主键 还是自增id?
由于每个非主键索引的叶子节点上都是主键的值。如果用身份证号做主键,那么每个二级索引的叶子节点占用约 20 个字节,而如果用整型做主键,则只要 4 个字节,如果是长整型(bigint)则是 8 个字节。
显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

小泉听懂了么? 对下面两个情况 你有啥理解?

重建索引k
alter table T drop index k;
alter table T add index(k);

重建主键索引
alter table T drop primary key;
alter table T add primary key(id);

重建索引k是合理的
而重置主键 就坑了 不论删除主键还是创建主键都会重建整个儿表.
不如用alter table T engine=InnoDB 为啥? 小泉回答
(alter table t engine=innodb,ALGORITHM=inplace;) 下期再见

为啥重置索引 索引可能因为删除、页分裂的原因,导致数据页空洞.重建索引的过程会创建一个新的索引 把数据按顺序插入. 这样数据页的利用率高 提高了索引的紧凑、更省空间

谈下一话题

mysql> create table T (
ID int primary key,
k int NOT NULL DEFAULT 0, 
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;

insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');

索引组织结构:
image.png

回表:回到主键索引树搜索的过程 select * from T where k betwee 3 and 5;
覆盖索引 select id from T where k betwee 3 and 5;

最左前缀原则

image.png

建立联合索引 如何安排索引字段顺序?

由于最左前缀原则
建立联合索引 (a,b,c) 相当于创建了 a ab abc三个索引
如果可以通过顺序安排 能够减少一个索引的维护 那很有必要考虑这个顺序问题

在考虑空间问题

如上面 name和age的联合索引 如果是个老外: 小泉纯一郎-梅川酷紫海梅游对象渣男斯基 占用空间太大了 那建议再建立一个age的单字段索引.

索引下推

姓张 十岁的所有男孩

mysql> select * from tuser where name like '张 %' and age=10 and ismale=1;

mysql5.6以前. 无索引下推


image.png

mysql5.6引入的 index condition pushdown 优化


image.png

以后 可能要分享内容:
普通索引 唯一索引如何选择 、 change buffer 与 redo log 、索引与优化器的爱恨情仇 、 前缀索引给覆盖索引使坏

你可能感兴趣的:(《SUO YIN》 --- ZXQ is a fool !)