学习记录-MySQL实战45讲 ~ 16

Extra 这个字段中的“Using filesort”表示的就是需要排序,MySQL 会给每个线程分配一块内存用于排序,称为 sort_buffer

select city,name,age from t where city='杭州' order by name limit 1000

从普通索引中找到 city='杭州'的主键id,去主键索引里找行记录,放入sort_buffer,重复,完成将sort_buffer中的数据按照name排序之后取出1000条返回

OPTIMIZER_TRACE可协助查看排序是否使用到外部文件的信息

如果查询要返回的字段很多的话,那么 sort_buffer 里面要放的字段数太多,这样内存里能够同时放下的行数很少,要分成很多个临时文件,排序的性能会很差

max_length_for_sort_data,是 MySQL 中专门控制用于排序的行数据的长度的一个参数,如果小于字段总长度,则先排序先保留排序字段和索引字段,最后返回1000条id再去主键索引补充其余字段信息

MySQL 之所以需要生成临时表,并且在临时表上做排序操作,其原因是原来的数据都是无序的

index city_user(city, name) -> 从普通索引中找到city='杭州'的主键id,去主键索引里找行记录,直接返回,只需要扫描1000行返回,因为索引有序,少了排序的过程

city_user_age(city, name, age) -> 覆盖索引是指,索引上的信息足够满足查询请求,不需要再回到主键索引上去取数据

1. 随机选取,order by rand() limit 3; 使用了内存临时表

Extra 字段显示 Using temporary,表示的是需要使用临时表;Using filesort,表示的是需要执行排序操作

rowid 名字的来历。实际上它表示的是:每个引擎用来唯一标识数据行的信息,对于有主键的 InnoDB 表来说,这个 rowid 就是主键 ID,对于没有主键的 InnoDB 表来说,这个 rowid 就是由系统生成的,EMORY 引擎不是索引组织表。在这个例子里面,你可以认为它就是一个数组。因此,这个 rowid 其实就是数组的下标

堆排序 VS 归并排序,取部分max/min vs 全局有序

2. 得到max/min id,用随机算法生成随机id,查id=随机id的返回,可能由于空洞导致不平均

3. 得到总行数,取随机一行,limit Y,1;按顺序一个一个地读出来,丢掉前 Y 个,然后把下一个记录作为返回结果,因此这一步需要扫描 Y+1 行。再加上,第一步扫描的 C 行,总共需要扫描 C+Y+1 行,执行代价比随机算法 1 的代价要高

对索引字段做函数操作,可能会破坏索引值的有序性,因此优化器就决定放弃走树搜索功能

即使是对于不改变有序性的函数,也不会考虑使用索引

在 MySQL 中,字符串和数字做比较的话,是将字符串转换成数字,where CAST(tradid AS signed int) = 110717 也会影响索引使用

两个表的字符集不同,一个是 utf8,一个是 utf8mb4,所以做表连接查询的时候用不上关联字段的索引,where CONVERT(traideid USING utf8mb4)=$L2.tradeid.value;,修改字符集或where d.tradeid=CONVERT(l.tradeid USING utf8) and l.id=2;

查询长时间不返回?

 - show processlist 可能锁了,杀掉持有进程;sys.schema_table_lock_waits 这张表,我们就可以直接找出造成阻塞的 process id,把这个连接用 kill 命令断开即可

 - 等 flush,flush tables 关闭 MySQL 里所有打开的表

 - 等行锁 lock in share mode,记录时要加读锁,如果这时候已经有一个事务在这行记录上持有一个写锁,我们的 select 语句就会被堵住,连接被断开的时候,会自动回滚这个连接里面正在执行的线程

 - 查询慢

    session B 更新完 100 万次,生成了 100 万个回滚日志 (undo log)。带 lock in share mode 的 SQL 语句,是当前读,因此会直接读到 1000001 这个结果,所以速度很快;而 select * from t where id=1 这个语句,是一致性读,因此需要从 1000001 开始,依次执行 undo log,执行了 100 万次以后,才将 1 这个结果返回

for update当前读加写锁

幻读,一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行

在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。上面 session B 的修改结果,被 session A 之后的 select 语句用“当前读”看到,不能称为幻读。幻读仅专指“新插入的行”

锁的设计是为了保证数据的一致性。而这个一致性,不止是数据库内部数据状态在此刻的一致性,还包含了数据和日志在逻辑上的一致性

即使把所有的记录都加上锁,还是阻止不了新插入的记录,这也是为什么“幻读”会被单独拿出来解决的原因

行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。因此,为了解决幻读问题,InnoDB 只好引入新的锁,也就是间隙锁 (Gap Lock)

间隙锁和行锁合称 next-key lock,每个 next-key lock 是前开后闭区间,间隙锁之间不冲突,间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的

间隙锁是在可重复读隔离级别下才会生效的

隔离级别设置为读提交的话,就没有间隙锁了。但同时,你要解决可能出现的数据和日志不一致问题,需要把 binlog 格式设置为 row

原文地址:https://www.cnblogs.com/it-worker365/p/14516148.html