zoukankan      html  css  js  c++  java
  • 表字符集与存储过程字符集不一致导致的存储过程执行缓慢

    昨天遇到个线上问题,某个存储过程执行异常缓慢,在数据量

    不到1K条的情况下竟然需要4min才能全部完成。

    查看了存储过程的具体操作,全部是删除逻辑,涉及大概十几张表

    删除操作。

    大致如下(项目代码不便透露,这里意思一下即可)

     1 CREATE  PROCEDURE deleteinfo(IN `aaax` varchar(50),IN `bbbx` varchar(50))
     2 BEGIN
     3   DECLARE aaa varchar(255); 
     4   DECLARE bbb   varchar(255); 
     5     
     6   SET aaa = aaax;
     7   SET bbb   = bbbx;
     8 
     9  Delete from table1
    10    where aaa = aaax
    11      and bbb = bbbx;
    12 
    13   Delete from table2
    14    where aaa = aaax
    15      and bbb = bbbx;
    16 
    17   Delete from Ptable3
    18    where aaa = aaax
    19      and bbb = bbbx;
    20 
    21 END

    经过确认,这几张表内的全部数据不过1K左右,但是执行时间却异常缓慢,

    于是我决定手动执行验证下时间,发现不过10s内就全部完毕,那么我猜测

    存储过程中一定发生了什么。

    经过进一步的排查,我们将目光放到了索引上,这几张表的索引都是没问题的,

    会不会存储过程中没有利用到索引呢?

    抱着这个疑问我查找了下索引失效的可能,最终发现,与存储过程和表的字符集有关。

    我们执行存储过程时,定义的参数没有指定字符集,则默认取character_set_server这个全局变量的值

    1   DECLARE aaa varchar(255); 
    2   DECLARE bbb   varchar(255); 

    我们可以通过下面语句来查看

    show variables like "%char%";

    接下来我们再来看下表的字符集,通过information_schema.columns可以查出

    1 SELECT DISTINCT
    2             TABLE_SCHEMA,TABLE_NAME,CHARACTER_SET_NAME
    3         FROM
    4             information_schema.`COLUMNS`
    5         WHERE
    6             TABLE_SCHEMA = (select databases())
    7         AND CHARACTER_SET_NAME != 'utf8mb4'

     我们发现很多表的字符集是utf-8,而存储过程内部参数确是utf-8mb4的,在这种情况下,

    mysql会将表转换为utf-8mb4(mylsq字符集转换遵循由小到大的规则,因为utf8mb4是utf8的超集,所以把

    utf8转换为utf8mb4),转换后,由于原来表上的索引依然是utf8的,这就导致了这些索引的失效。

    于是,我们终于找出了这个问题的罪魁祸首,接下来,我们看下怎么处理这个问题,这里有2个方案

    (1)修改character_set_server=utf8,然后重建存储过程(存储过程的字符集是在新建时读取的character_set_server因此不重建则无效)

    (2)将表的字符集改为utf8mb4

    经过考量后决定修改表的字符集(character_set_server修改需重启数据库服务,线上项目改动风险过大),可以通过以下语句实现

    alter table table_name convert to charset utf8mb4;

    但项目上表较多的时候一张张表修改显然是不现实的,因此这里提供下批量生成语句,

    可以直接将非utf8mb4的表查询出来并生成修改语句(修改前建议先备份)

     1 SELECT
     2     CONCAT(
     3         "ALTER TABLE `",
     4         tb.TABLE_SCHEMA,
     5         "`.`",
     6         tb.TABLE_NAME,
     7         "` CONVERT TO CHARACTER SET utf8mb4;"
     8     )
     9 FROM
    10     (
    11         SELECT DISTINCT
    12             TABLE_SCHEMA,TABLE_NAME
    13         FROM
    14             information_schema.`COLUMNS`
    15         WHERE
    16             TABLE_SCHEMA = (select database())
    17         AND CHARACTER_SET_NAME != 'utf8mb4'
    18 and TABLE_NAME 
    19 not in (select TABLE_NAME from information_schema.VIEWS where TABLE_SCHEMA = (select database()))
    20     ) as tb;

    最后,这个问题时由于存储过程字符集utf8mb4,表字符集utf8引起的,但是反过来则不会有这个问题,因为utf8mb4是兼容utf8的。

    争取早日不再是一只菜鸡
  • 相关阅读:
    IIS 6.0下安装SSL数字证书实现https访问
    使用SQL2005自带扩展函数对字符串进行MD5加密(转)
    Posix多线程编程学习笔记(三)—信号灯(1)--转自湖光倒影
    利用pthread_mutex对多进程上锁
    ObjectiveC中的锁
    Linux内存管理之mmap详解
    cocoa应用程序生命周期
    多线程编程互斥锁
    [New Book]Flex第一步 国内第一本关于Flex的书籍
    ASP.NET中实现二级或多级域名(修改UrlRewrite)
  • 原文地址:https://www.cnblogs.com/jchen104/p/15028753.html
Copyright © 2011-2022 走看看