一、优化器的逻辑
根据扫描行数和是否使用主键索引等因素综合决定的。
1.怎么扫描行数?
扫描行数的判断就是根据区分度,区分度是由基数决定的,基数就是一个索引上不同值得个数,基数越大,说明区分度越好。
2.基数是怎么得来的?
基数使用采样统计得来的,采样统计就是随机抽查几个索引的基数得到平均值。采样统计会采取N个样本,当变更数据超过1/M时,就会重新统计。
索引统计有两种方式,一种是持久化储存,一种是存入内存。
设置InnoDB_starts_persistet参数:
为on,表示持久化,默认N是20,M是10;
为off,表示存入内存,默认N是8,M是16;
3.怎么更正选择索引
analyze table t ;
二、索引选择异常处理
1.使用force index
强行使用a为索引;
select * from t force index(a) where a between 10000 and 20000;
问题是不便于迁移,不够敏捷;
2.引导使用索引
select * form t where a between 1 and 500 and b between 5000 and 10000 order by b limit 1;
改成
select * form t where a between 1 and 500 and b between 5000 and 10000 order by b,a limit 1;
3.新建或删除一个索引
新建一个索引 或者删除一个没有必要的索引。
三、创建一个实例验证
1.新建一个表t
CREATE TABLE
t
(
id
int(11) AUTO_INCREMENT NOT NULL,
a
int(11) DEFAULT NULL,
b
int(11) DEFAULT NULL,
PRIMARY KEY (id
),
KEYa
(a
),
KEYb
(b
)
) ENGINE=InnoDB;
2.插入10万条数据
delimiter ;;
create procedure idata()
begin
declare i int;
set i=1;
while(i<=100000)do
insert into t values(i, i, i);
set i=i+1;
end while;
end;;
delimiter ;
call idata();
3.开始执行事务a和事务b
窗口a:
begin;
start transaction with consistent snapshot;
窗口b:
delete from t;
call idata();
explain select * from t where a between 10000 and 20000;
窗口a:
commit;
set long_query_time=0;
select * from t where a between 10000 and 20000; /Q1/
select * from t force index(a) where a between 10000 and 20000;/Q2/