mysql怎么批量看索引状态_MySQL中怎样快速找出超长索引

大家好,我是知数堂SQL 优化班老师 网名:骑龟的兔子

46cdd68ce58a13c33d3f18b072505dcc.png

需求:

想要查找哪些索引太长了,这个SQL在5.7下跑的特别慢,8.0则挺快的,帮看下有啥优化方案没

具体SQL 和执行计划如下 :

SELECT c.TABLE_SCHEMA AS DB,c .TABLE_NAME AS TBL,c.COLUMN_NAME AS COL,c.CHARACTER_OCTET_LENGTH AS COL_LEN_BYTES,s.INDEX_NAME,s.SUB_PART * CHARACTER_OCTET_LENGTH/CHARACTER_MAXIMUM_LENGTH AS SUB_PART_LENFROM information_schema.COLUMNS cINNER JOIN information_schema.STATISTICS s USING(TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME)INNER JOIN information_schema.TABLES t USING(TABLE_SCHEMA, TABLE_NAME)WHERE c.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND c.DATA_TYPE IN ("varchar", "char", "text", "blob")AND ((CHARACTER_OCTET_LENGTH > 50 and SUB_PART is null) orSUB_PART * CHARACTER_OCTET_LENGTH/CHARACTER_MAXIMUM_LENGTH > 50)AND t.TABLE_ROWS > 10000ORDER BY COL_LEN_BYTES DESC;执行计划*************************** 1. row ***************************id: 1select_type: SIMPLEtable: cpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases; Using temporary; Using filesort*************************** 2. row ***************************id: 1select_type: SIMPLEtable: spartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases; Using join buffer (Block Nested Loop)*************************** 3. row ***************************id: 1select_type: SIMPLEtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases; Using join buffer (Block Nested Loop)3 rows in set, 1 warning (0.01 sec)select count(*) from information_schema.tables;+----------+| count(*) |+----------+| 33600 |+----------+select count(*) from information_schema.COLUMNS;+----------+| count(*) |+----------+| 342967 |+----------+select count(*) from information_schema.STATISTICS;+----------+| count(*) |+----------+| 135167 |+----------+

上面的SQL 运行450+ s 也运行不出来,最后kill掉了。

我们初步分析一下,从执行计划中 可以看出三个表都是ALL 所以很慢

那添加索引不就行了吗,因为是系统表,所以不能随便添加!

那该怎么办?想到了AUTOKEY 就是临时索引,那思路就是改写SQL

达到生成临时索引,最终达到优化效果

改写的SQL 如下

SELECT c.TABLE_SCHEMA AS DB, c.TABLE_NAME AS TBL, c.COLUMN_NAME AS COL, c.CHARACTER_OCTET_LENGTH AS COL_LEN_BYTES, s.INDEX_NAME,s.SUB_PART * c.CHARACTER_OCTET_LENGTH/c.CHARACTER_MAXIMUM_LENGTH AS SUB_PART_LENFROM( select c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME ,c.CHARACTER_OCTET_LENGTH ,c.CHARACTER_MAXIMUM_LENGTH , c.DATA_TYPEfrominformation_schema.COLUMNS cWHERE c.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND c.DATA_TYPE IN ("varchar", "char", "text", "blob")limit 10000000000) cINNER JOIN(select s.TABLE_SCHEMA, s.TABLE_NAME, s.COLUMN_NAME ,s.SUB_PART,s.INDEX_NAMEfrominformation_schema.STATISTICS sWHERE s.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')limit 10000000000)s USING(TABLE_SCHEMA, TABLE_NAME, COLUMN_NAME)INNER JOIN information_schema.TABLES t USING(TABLE_SCHEMA, TABLE_NAME)WHERE c.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND c.DATA_TYPE IN ("varchar", "char", "text", "blob")AND ((c.CHARACTER_OCTET_LENGTH > 50 and s.SUB_PART is null) ors.SUB_PART * c.CHARACTER_OCTET_LENGTH/c.CHARACTER_MAXIMUM_LENGTH > 50)AND t.TABLE_ROWS > 10000ORDER BY COL_LEN_BYTES DESC;*************************** 1. row ***************************id: 1select_type: PRIMARYtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases; Using temporary; Using filesort*************************** 2. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 388ref: information_schema.t.TABLE_SCHEMA,information_schema.t.TABLE_NAMErows: 2filtered: 50.00Extra: Using where*************************** 3. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 582ref: information_schema.t.TABLE_SCHEMA,information_schema.t.TABLE_NAME,c.COLUMN_NAMErows: 2filtered: 100.00Extra: Using where*************************** 4. row ***************************id: 3select_type: DERIVEDtable: spartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases*************************** 5. row ***************************id: 2select_type: DERIVEDtable: cpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases5 rows in set, 1 warning (0.01 sec)

结果来了 2463 rows in set, 417 warnings (23.39 sec)

但是经过几次运行之后 有时候是40多秒有时候甚至达到了166s 非常不稳定!

那分析下上面这个SQL的问题在哪里?

问题就是生成的AUTO KEY的量相对来说非常大!因为没有进行任何过滤

那现在的思路就是 对生成的AUTOKEY的量 进行减少

我们通过相对小的表TABLES 表生成autokey 之后 STATISTICS ,COLUMNS

表分别跟 TABLES 表进行JOIN 然后减少数据量 达到减少生成AUOKEY 的量 减少 达到优化目的 ,具体的方法如下

select count(1)from(select s.TABLE_SCHEMA, s.TABLE_NAME, s.COLUMN_NAME ,s.SUB_PART,s.INDEX_NAMEfrominformation_schema.STATISTICS sWHERE s.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test'))s straight_join(select t.TABLE_SCHEMA, t.TABLE_NAMEfrominformation_schema.TABLES tWHERE t.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND t.TABLE_ROWS > 10000limit 10000000000) t on s.TABLE_SCHEMA=t.TABLE_SCHEMA and s.TABLE_NAME =t.TABLE_NAME*************************** 1. row ***************************id: 1select_type: PRIMARYtable: spartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases*************************** 2. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 388ref: information_schema.s.TABLE_SCHEMA,information_schema.s.TABLE_NAMErows: 2filtered: 100.00Extra: Using index*************************** 3. row ***************************id: 3select_type: DERIVEDtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases3 rows in set, 1 warning (0.00 sec)+----------+| count(1) |+----------+| 7478 |+----------+1 row in set, 40 warnings (7.52 sec)select count(1)from( select c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME ,c.CHARACTER_OCTET_LENGTH ,c.CHARACTER_MAXIMUM_LENGTH , c.DATA_TYPEfrominformation_schema.COLUMNS cWHERE c.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND c.DATA_TYPE IN ("varchar", "char", "text", "blob")) c straight_join(select t.TABLE_SCHEMA, t.TABLE_NAMEfrominformation_schema.TABLES tWHERE t.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND t.TABLE_ROWS > 10000limit 10000000000) t on c.TABLE_SCHEMA=t.TABLE_SCHEMA and c.TABLE_NAME =t.TABLE_NAME*************************** 1. row ***************************id: 1select_type: PRIMARYtable: cpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases*************************** 2. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 388ref: information_schema.c.TABLE_SCHEMA,information_schema.c.TABLE_NAMErows: 2filtered: 100.00Extra: Using index*************************** 3. row ***************************id: 3select_type: DERIVEDtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases3 rows in set, 1 warning (0.00 sec)+----------+| count(1) |+----------+| 8106 |+----------+1 row in set, 417 warnings (8.62 sec)

最终SQL 如下

SELECT c.TABLE_SCHEMA AS DB, c.TABLE_NAME AS TBL, c.COLUMN_NAME AS COL, c.CHARACTER_OCTET_LENGTH AS COL_LEN_BYTES, s.INDEX_NAME,s.SUB_PART * c.CHARACTER_OCTET_LENGTH/c.CHARACTER_MAXIMUM_LENGTH AS SUB_PART_LENfrom( select c.TABLE_SCHEMA, c.TABLE_NAME, c.COLUMN_NAME ,c.CHARACTER_OCTET_LENGTH ,c.CHARACTER_MAXIMUM_LENGTH , c.DATA_TYPEfrominformation_schema.COLUMNS cWHERE c.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND c.DATA_TYPE IN ("varchar", "char", "text", "blob")) c straight_join(select t.TABLE_SCHEMA, t.TABLE_NAMEfrominformation_schema.TABLES tWHERE t.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND t.TABLE_ROWS > 10000limit 10000000000) t on c.TABLE_SCHEMA=t.TABLE_SCHEMA and c.TABLE_NAME =t.TABLE_NAMEstraight_join(select s.*from(select s.TABLE_SCHEMA, s.TABLE_NAME, s.COLUMN_NAME ,s.SUB_PART,s.INDEX_NAMEfrominformation_schema.STATISTICS sWHERE s.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test'))s straight_join(select t.TABLE_SCHEMA, t.TABLE_NAMEfrominformation_schema.TABLES tWHERE t.TABLE_SCHEMA not in ('information_schema','performance_schema','mysql','sys', 'test')AND t.TABLE_ROWS > 10000limit 10000000000) t on s.TABLE_SCHEMA=t.TABLE_SCHEMA and s.TABLE_NAME =t.TABLE_NAMElimit 10000000000) son c.TABLE_SCHEMA=s.TABLE_SCHEMA and c.TABLE_NAME=s.TABLE_NAME and c.COLUMN_NAME =s.COLUMN_NAMEwhere((c.CHARACTER_OCTET_LENGTH > 50 and s.SUB_PART is null) ors.SUB_PART * c.CHARACTER_OCTET_LENGTH/c.CHARACTER_MAXIMUM_LENGTH > 50)*************************** 1. row ***************************id: 1select_type: PRIMARYtable: cpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases*************************** 2. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 388ref: information_schema.c.TABLE_SCHEMA,information_schema.c.TABLE_NAMErows: 2filtered: 100.00Extra: Using index*************************** 3. row ***************************id: 1select_type: PRIMARYtable: partitions: NULLtype: refpossible_keys: key: key_len: 582ref: information_schema.c.TABLE_SCHEMA,information_schema.c.TABLE_NAME,information_schema.c.COLUMN_NAMErows: 2filtered: 100.00Extra: Using where*************************** 4. row ***************************id: 4select_type: DERIVEDtable: spartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_frm_only; Scanned all databases*************************** 5. row ***************************id: 4select_type: DERIVEDtable: partitions: NULLtype: refpossible_keys: key: key_len: 388ref: information_schema.s.TABLE_SCHEMA,information_schema.s.TABLE_NAMErows: 2filtered: 100.00Extra: Using index*************************** 6. row ***************************id: 6select_type: DERIVEDtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases*************************** 7. row ***************************id: 3select_type: DERIVEDtable: tpartitions: NULLtype: ALLpossible_keys: NULLkey: NULLkey_len: NULLref: NULLrows: NULLfiltered: NULLExtra: Using where; Open_full_table; Scanned all databases7 rows in set, 1 warning (0.00 sec)

看起来稳定了,跑了几次,都没超过15秒

我的新一轮的SQL 优化课 即将在春节后开课

我是知数堂SQL 优化班老师~ ^^

如有关于SQL优化方面疑问和一起交流的请加 并且 @兔子@知数堂SQL优化

高性能MySQL,SQL优化群 有叶金荣,吴炳锡 两位大神坐镇 :579036588

欢迎加入 知数堂大家庭。

我的微信公众号:SQL开发与优化(sqlturning)

扫码直达宝藏课程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值