有时候只查询一行语句,执行也慢

有时候只查询一行语句,执行也慢

1 查询长时间不返回

  • 假如有一个SQL

    mysql> select * from t where id=1;
    
    • 查询结果长时间不返回

    • 一般是表t被锁住了,这时候执行show processlist

1.1 等MDL锁

  • 使用 show processlist 命令查看 Waiting for table metadata lock 的示意图。

    • 出现这个状态表示,现在有一个线程正在表t上请求或持有MDL写锁,把select堵住了
    • 查询sys.schema_table_lock_waits这张表,找到阻塞的process id,用kill命令将连接断开

1.2 等flush

  • 执行SQL

    select * from information_schema.processlist where id=1;
    
    • 查出来这个线程的状态是 Waiting for table flush,你可以设想一下这是什么原因。

    • 这个状态表示的是,现在又一个线程正要堆表t做flush操作,MySQL里面堆表做flush操作的用法,一般有以下两个:

      
      flush tables t with read lock;
      
      flush tables with read lock;
      
      //flush tables 是将buffer pool的数据刷回到磁盘中
      
    • 这两个flush语句,如果指定表t的话,代表的是只关闭表t;如果没有指定具体的表明,则表示关闭MySQL里所有打开的表。

      • 正常情况下这语句执行很快,除非也是被堵住了。
      • 所以,出现 Waiting for table flush 状态的可能情况是:有一个 flush tables 命令被别的语句堵住了,然后它又堵住了我们的 select 语句。
  • 复现步骤

    1. 在session A中,每行都调用一次sleep(1),这样这个语句默认要执行10万秒,在这期间表t一直被session A打开。

    2. show processlist

    3. 将sessionA 线程kill 13

      KILL [CONNECTION | QUERY] processlist_id
       kill query 13 //连接有SQL执行会继续执行
       kill 13 //不管有没有,都会将线程杀掉。
      

1.3 等行锁

  • SQL

     select * from t where id=1 lock in share mode; 
     
      select k from t where id=1 lock in share mode; 
      select k from t where id=1 for update; 
      select 语句如果加锁,是当前读;
      分别加了读锁(S 锁,共享锁)和写锁(X 锁,排他锁)。
    
    • 由于id = 1 这个记录加了读锁,如果这时候已经有一个事务在这行记录上持有一个读锁,我们的select 语句就会被锁住。

    • 查询语句被锁住:

    • 因此是session A启动事务,占有写锁后,还不进行提交,导致了session B被锁住。

    • 查询占用

      select * from t sys.innodb_lock_waits where locked_table='`test`.`t`'\G
      
    • 然后将query kill掉,需要直接进行kill id ,直接将连接断开后,才会事务回滚释放锁。

2 查询慢

  •  select * from t where c=50000 limit 1;
    
  • 由于字段c上没有索引,所以这个语句直走id主键索引,进行全表扫描。

    • 扫描行数多,执行慢。坏查询不一定是慢查询
  • diselect * from t where id=1;
    select * from t where id=1 lock in share mode;
    
    • 第一条语句慢查询:

    • 第二条语句慢查询:

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b9UYTdjJ-1656643464196)(https://cdn.jsdelivr.net/gh/Cltlient/PiGoCDN/img/20220113171449.png)]

    • 执行结果:

      img

  • 复现步骤:img

    • session A 先用 start transaction with consistent snapshot 命令启动了一个事务,之后 session B 才开始执行 update 语句。、
    • session B执行万100万次update 后,id = 1 这一行状态如下:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P5g5ZU38-1656643464197)(https://cdn.jsdelivr.net/gh/Cltlient/PiGoCDN/img/20220113171702.png)]
    • session B更新完100万次,生成了100万个回滚日志(undo log)。
    • 带lock in share mode的SQL语句,是当前读,因此会直接读到100001这个结果,所以速度很快;
    • select * from where id =1 这个语句,是一致性读,因此需要从100001开始,一次执行undolog,执行100万次,将1这个记过返回。

3 小结:

  • 差一行:可能会出现的被锁住和执行慢的例子,主要是表锁、行锁和一致性读的概念。

  • 问题:

    • 举例加锁读的时候,用的是这个语句,select * from t where id=1 lock in share mode。由于 id 上有索引,所以可以直接定位到 id=1 这一行,因此读锁也是只加在了这一行上。

    • 但如果是下面的 SQL 语句,

      
      begin;
      select * from t where c=5 for update;
      commit;
      
    • 这个语句怎么加锁的呢?加的锁又是什么时候释放?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
优化和调优 SQL 查询的方式有很多,以下是一些常见的方法: 1. 确保正确使用索引:索引可以大大加快查询速度。确保表中的列上有适当的索引,并且查询中的条件和连接列也使用了索引。 2. 优化查询语句:避免不必要的查询和连接,尽量简化查询语句,只选择需要的列和行。 3. 避免全表扫描:确保查询条件能够利用索引,避免对整个表进行扫描。可以使用 EXPLAIN 或者执行计划来查看查询是否使用了索引。 4. 分析和优化表结构:检查表结构,确保合理地设计了主键、外键和索引。根据查询的需求,可能需要调整表结构,增加或删除索引。 5. 优化数据类型:使用合适的数据类型可以减少存储空间和提高查询性能。选择最小可能的数据类型,并避免存储冗余数据。 6. 使用合适的连接方式:根据查询需求选择合适的连接方式,如 INNER JOIN、LEFT JOIN、RIGHT JOIN 等。有时候使用子查询或者 EXISTS 子句可以更高效地实现查询。 7. 分页查询优化:对于大数据量的分页查询,可以使用游标或者 LIMIT OFFSET 的方式来优化查询速度。 8. 使用缓存:如果查询的结果是经常被访问的,可以考虑使用缓存技术,将结果缓存起来,减少数据库查询次数。 9. 定期维护数据库:定期进行数据库的优化、索引的重建、统计信息的更新等维护操作,保持数据库的性能。 以上是一些常见的优化和调优方式,具体的优化策略还需要根据具体的查询数据库环境来确定。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值