业务场景:基于字符串字段做查询。例如邮箱登录等等。
前缀索引的优势:相对于整个字段索引,前缀索引的占用空间更小。
前缀索引带来的问题:区分度过低的时候会额外扫描次数。
使用前缀索引需要定义好长度,就可以节省空间又不用额外增加太多查询成本。
区分度语句:
select
count(distinct left(field,4))as L4,
count(distinct left(field,5))as L5,
count(distinct left(field,6))as L6,
count(distinct left(field,7))as L7,
from table;
使用前缀索引 = 去掉索引覆盖,因为无法确定前缀索引是否覆盖全部内容。
其他问题:例如身份证字段前6位区分不够好,加到12个字段又会导致过大,页存放数据变少,查询效率变低。
alter table t add id_card_crc int unsigned, add index(id_card_crc);
相同点:不支持范围查询,
小总结:
维护一个学校的学生信息数据库,学生登录名的统一格式是”学号@gmail.com", 而学号的规则是:十五位的数字,其中前三位是所在城市编号、第四到第六位是学校编号、第七位到第十位是入学年份、最后五位是顺序编号。
系统登录的时候都需要学生输入登录名和密码,验证正确后才能继续使用系统。就只考虑登录验证这个行为的话,你会怎么设计这个登录名的索引呢?
我的回答:学号只有后五位是区分度,根据所学,使用第三种倒序存储。
标准答案:而其实在此基础上,可以用数字类型来存这9位数字。比如201100001,这样只需要占4个字节。其实这个就是一种hash,只是它用了最简单的转换规则:字符串转数字的规则,而刚好我们设定的这个背景,可以保证这个转换后结果的唯一性
场景:一条SQL语句,正常执行的时候特别快,但是有时也不知道怎么回事,它就会变得特别慢,并且这样的场景很难复现,它不只随机,而且持续时间还很短。
脏页
参数 innodb_file_per_table
innodb_file_per_table
show VARIABLES where Variable_name = 'innodb_file_per_table'
我建议你不论使用MySQL的哪个版本,都将这个值设置为ON。
show table status
MySQL会给每个线程分配一块内存用于排序,称为sort_buffer。
show VARIABLES where Variable_name = 'sort_buffer_size'
对于对 InnoDB I 表来说 表 ,执行全字段排序会减少磁盘访问,因此会被优先选择。
建表语句
CREATE TABLE `t_2001` (`id` INT ( 11 ) NOT NULL,`c` INT ( 11 ) DEFAULT NULL,`d` INT ( 11 ) DEFAULT NULL,PRIMARY KEY ( `id` ),KEY `c` ( `c` )
) ENGINE = INNODB;
数据
insert into t_2001 values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);
BEGIN;SELECT* FROMt_2001 WHEREd = 5 FOR UPDATE;
COMMIT;
这个语句会命中d=5的这一行,对应的主键id=5,因此在select 语句执行完成后,id=5这一行会加一个写锁,而且由于两阶段锁协议,这个写锁会在执行commit语句的时候释放。
由于字段d上没有索引,因此这条查询语句会做全表扫描。那么,其他被扫描到的,但是不满足条件的5行记录上,会不会被加锁呢?
一个假设的场景,实际运行B和C会阻塞。
幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。(for update)
上面session B的修改结果,被session A之后的select语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”。
语义:我要将 d=5的所有行锁住,实际上没有锁住。
select * from t_2001 where d= 5 for update
一致性:
也就是说,即使把所有的记录都加上锁,还是阻止不了新插入的记录
为了解决幻读问题,InnoDB只好引入新的锁,也就是间隙锁(Gap Lock),顾名思义,间隙锁,锁的就是两个值之间的空隙。比如文章开头的表t,初始化插入了6个记录,这就产生了7个间隙。
当你执行 select *fromt where d=5 for update的时候,就不止是给数据库中已有的6个记录加上了行锁,还同时加了7个间隙锁。这样就确保了无法再插入新的记录。
间隙锁和行锁合称next-key lock,每个next-key lock是前开后闭区间。