此等锁表必须有两个条件:
首先历史原因,线上加索引是用了一个存储过程:
摒弃一切无关要素,我们只看核心语句:
线上用的就是这么一个语句添加索引的。
首先,添加索引为什么会锁表呢?查阅一些资料说,如果当前表正在执行一个慢查询,此时添加索引,就可能会锁表。
我尝试在测试环境重现了一下。
首先,我在b_regbroker_cst_proj这个表执行了一个慢查询事务。
这个查询正常完成要9s左右,够慢了,满足要求。
然后我要做的事情,就是在查询未完成的时间,给b_regbroker_cst_proj这个表添加索引。
好了,来试试,我先开启事务,先不提交。
然后创建索引:
哦耶,so funny。
此时无论这个表执行什么查询,都会卡住了:
查了一下下面这个lock的原因:
有没有更好的加索引解决方式呢?查文档
文档
mysql自5.6之后变提供了解决方式,运行线上无锁添加索引。
重点说两个参数:
好了,试下有没有用。
哈哈哈,卵用都没有。
我觉得我是理解错了,人家的无锁加索引,只是说加索引的语句不加锁,避免此时有update、insert、delete语句也持锁从而相互形成死锁。但是目前的问题是,有事务持了表锁,创建索引需要等待。等该事务提交,索引就能创建成功。但是在这个等待时间,其它sql都执行不了,这个很坑啊~~
结论:
总之,alter table的语句是很危险的(其实他的危险其实是未提交事物或者长事务导致的),在 *** 作之前最好确认对要 *** 作的表没有任何进行中的 *** 作、没有未提交事务、也没有显式事务中的报错语句。如果有alter table的维护任务,在无人监管的时候运行,最好通过lock_wait_timeout设置好超时时间,避免长时间的metedata锁等待。
加索引要避免锁表,需要先确定此时没有慢查询事务未提交,如果这个查询卡了30分钟,那么整个表的所有业务都会卡30分钟,这是很变态的。
所以大表加索引还是在没人用的时间加比较安全,要不就是先创建副本,再将表名改掉。
应该是没有默认索引,建立主键或者索引之后,oracle会在单独的一块区域建立索引的数据,索引的数据和表的数据是分别存放的,不是在一起的,索引的数据就对应表的主键或者其他索引,例如,你的表里有100条数据,并且有主键,那么在索引的区域就会有100条数据和它们对应,并且由于是主键数据,所以每条数据都是唯一的,不会重复,数据检索的时候,先去检索索引区,因为那里的数据比较少,所以速度很快。但如果没有主键,一个表中可以有重复的数据,所以系统也不知道按照什么样的规则自动建索引,就不会有默认的索引,oracle每次查询都会进行全表查询。欢迎分享,转载请注明来源:内存溢出
评论列表(0条)