快乐学习
前程无忧、中华英才非你莫属!

找出MySQL使用率不高以及重复的索引

5.6版本

SQL分析未使用索引

select distinct  
    mysql.innodb_index_stats.table_name,  
    mysql.innodb_index_stats.index_name  
from  
    mysql.innodb_index_stats  
where  
    concat(mysql.innodb_index_stats.index_name,  
            mysql.innodb_index_stats.table_name) not in (select   
            concat(information_schema.statistics.index_name,  
                        information_schema.statistics.table_name)  
        from  
            information_schema.statistics)  
        and mysql.innodb_index_stats.index_name <> &apos;GEN_CLUST_INDEX&apos;;

这里我们看到了用户统计的一个限制,它只能跟踪索引键的直接查找,而不能在约束检查期间完成查找。这就是FK被标记为未使用的原因,这意味着在基准测试期间所有其他指标都被使用了。

第二个限制是使用分区表,不能从这些表中获得索引统计信息的使用情况。


  MySQl索引分析工具对比

 在mysql中如何找出未使用或使用次数很少的索引,这样文章比较多,但很少文章提到用这些方法存在的风险。

   http://www.mysqlperformanceblog.com/2012/06/30/find-unused-indexes/

   http://www.mysqlperformanceblog.com/2012/12/05/quickly-finding-unused-indexes-and-estimating-their-size/

   http://www.mysqlperformanceblog.com/2009/06/26/check-unused-keys-a-tool-to-interact-with-index_statistics/

   这篇文章主要记录,我对如何找未使用索引的理解及风险(目前还未找到理想方法),能像oracle保存执行计划,根据执行计划(v$sql_plan)来判断索引使用情况是比较安全。当然oracle的index monitor特性类似percona的userstat有比较大的风险。

   以下四个工具(方法)是在mysql找未使用索引比较方便,但都存在一定风险

   1、mysqlidxchx

   2、pt-index-usage

   3、userstat

   4、check-unused-keys

   1、mysqlidxchx工具很长时间没有更新,但主要用来分析general log、slow.log,来判断实例中那个索引是可以删除,但这个工具没有经过实战,风险很大。

   2、pt-index-usage原理来类似mysqlidxchx,执行过程中性能消耗比较严重,如果要在生产库上部署,最好在凌晨业务低锋时使用,pt-index-usage只支持slow.log格式的文件,如果要全面分析整个实例索引使用情况,需要long_query_time设置成0,才能把所以的sql记录下来,但同时会对磁盘空间造成压力,同时pt-index-usage对大文件分析就是件痛苦的事。当然pt-index-usage可以考虑部分表索引使用情况的确认。

   3、最看好的userstat,收集信息性能优越,成本低。这个patch是google贡献的(userstat_running),percona把它改名成userstat,默认是不开启的,开启是会收集客户端、索引、表、线程信息存储在CLIENT_STATISTICS、INDEX_STATISTICS、TABLE_STATISTICS、THREAD_STATISTICS。Userstat的bug导致的问题太严重,直接导致mysql crash,到目前淘宝生产环境还没有使用。

   4、Ryan Lowe的check-unused-keys脚本基于userstat,能够比较方便输出需要删除的索引。

   小结:mysql能把每条sql执行计划保存在性能视图中,写入性能视图成本是非常小,用户可以根据执行计划来判断索引使用情况,分析执行计划突变的监控。


    pt-index-usage使用

    Percona工具包有一个工具来检查慢速查询日志中索引的使用情况。这个概念很容易理解。pt-index-usage读取慢查询日志,并用EXPLAIN执行每个查询,询问MySQL将使用哪个索引。在这个过程的最后,你将得到一个输出,其中包含一个未使用的索引列表。这是一个例子:

    Shell
    root@debian:/var/log# pt-index-usage slow.log
    slow.log:  11% 03:58 remain
    slow.log:  21% 03:43 remain
    slow.log:  32% 03:09 remain
    [...]
    ALTER TABLE `tpcc`.`order_line` DROP KEY `fkey_order_line_2`; -- type:non-unique
    ALTER TABLE `tpcc`.`orders` DROP KEY `idx_orders`; -- type:non-unique
    ALTER TABLE `tpcc`.`stock` DROP KEY `fkey_stock_2`; -- type:non-unique

    如果将这些结果与前面的例子进行比较,则会有一些差异,这些原因是:

  • pt-index-usage使用EXPLAIN和用户统计为每个索引读取的行数。所以我们将估算与实际数据进行比较。

  • 正如我之前所说的,EXPLAIN是来自优化器的估计,有时真正的查询可以使用不同的执行计划。

  • pt-index-usage试图将非SELECT查询转换成SELECT查询,并不总是可能得到一个完美的转换,所以可能会有一些差异。

  • 请谨慎使用唯一索引,因为它们可能不用于索引查找,但您的应用程序可能需要它们来避免列上的重复。

    考虑到根据日志的大小,服务器将需要大量的处理时间和CPU电源,所以我建议你不要在生产服务器上使用。在具有相似数据结构和大小的从属或测试环境中运行它。

    结论

    我们已经学会了如何使用不同的方法找到未使用的索引,并且我们也已经知道我们不应该从字面上来遵循工具的建议。这些工具在这里帮助我们,之后是我们的工作,检查和测试测试环境的变化,以衡量对性能的影响。你不需要删除所有这样的索引,但是它让你知道你应该评估哪一个。好的工具可以帮助我们进行评估,包括pt-log-playerpt-upgrade

    值得一提的是,要花费足够长的日志或统计来分析所有相关的工作量。在某些情况下,有一天或一周运行一次的流程,我们应该在分析报告中提供这些信息。


MySQL Utilities — 优化重复冗余索引

MySQL允许用户创建重复或冗余的索引。重复索引是没有优势的,在某些情况下,冗余的索引可能是有益的。当然啦,这两者都是有缺点的。重复和冗余索引会减慢更新和插入操作的。因此,找到并删除它们是比较好的。

执行此任务的利器是mysqlindexcheck,自动检查并生产更改语句。


实例

表结构如下所示:

CREATE TABLE `test_db`.`indexcheck_test`(
       `emp_id` INT(11) NOT NULL,
       `fiscal_number` int(11) NOT NULL,
       `name` VARCHAR(50) NOT NULL,
       `surname` VARCHAR (50) NOT NULL,
       `job_title` VARCHAR (20),
       `hire_date` DATE default NULL,
       `birthday` DATE default NULL,
       PRIMARY KEY (`emp_id`),
       KEY `idx_fnumber`(`fiscal_number`),
       UNIQUE KEY `idx_unifnumber` (`fiscal_number`),
       UNIQUE KEY `idx_uemp_id` (`emp_id`),
       KEY `idx_full_name` (`name`, `surname`),
       KEY `idx_full_name_dup` (`name`, `surname`),
       KEY `idx_name` (`name`),
       KEY `idx_surname` (`surname`),
       KEY `idx_reverse_name` (`surname`,`name`),
       KEY `ìdx_id_name` (`emp_id`, `name`),
       KEY `idx_id_hdate` (`emp_id`, `hire_date`),
       KEY `idx_id_bday` (`emp_id`, `birthday`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

索引分析:

shell> mysqlindexcheck --server=test_user@localhost:13010 test_db.indexcheck_test
# Source on localhost: ... connected.
# The following indexes are duplicates or redundant for table test_db.indexcheck_test:
#
CREATE INDEX `idx_uemp_id` ON `test_db`.`indexcheck_test` (`emp_id`) USING BTREE
#     may be redundant or duplicate of:
ALTER TABLE `test_db`.`indexcheck_test` ADD PRIMARY KEY (`emp_id`)
#
CREATE INDEX `idx_fnumber` ON `test_db`.`indexcheck_test` (`fiscal_number`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `idx_unifnumber` ON `test_db`.`indexcheck_test` (`fiscal_number`) USING BTREE
#
CREATE INDEX `idx_full_name_dup` ON `test_db`.`indexcheck_test` (`name`, `surname`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `idx_full_name` ON `test_db`.`indexcheck_test` (`name`, `surname`) USING BTREE
#
CREATE INDEX `idx_name` ON `test_db`.`indexcheck_test` (`name`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `idx_full_name` ON `test_db`.`indexcheck_test` (`name`, `surname`) USING BTREE
#
CREATE INDEX `idx_surname` ON `test_db`.`indexcheck_test` (`surname`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `idx_reverse_name` ON `test_db`.`indexcheck_test` (`surname`, `name`) USING BTREE
#
ALTER TABLE `test_db`.`indexcheck_test` ADD PRIMARY KEY (`emp_id`)
#     may be redundant or duplicate of:
CREATE INDEX `ìdx_id_name` ON `test_db`.`indexcheck_test` (`emp_id`, `name`) USING BTREE
#
CREATE INDEX `idx_id_hdate` ON `test_db`.`indexcheck_test` (`emp_id`, `hire_date`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `ìdx_id_name` ON `test_db`.`indexcheck_test` (`emp_id`, `name`) USING BTREE
#
CREATE INDEX `idx_id_bday` ON `test_db`.`indexcheck_test` (`emp_id`, `birthday`) USING BTREE
#     may be redundant or duplicate of:
CREATE INDEX `ìdx_id_name` ON `test_db`.`indexcheck_test` (`emp_id`, `name`) USING BTREE
# The following indexes for table test_db.indexcheck_test contain the clustered index and
# might be redundant:
#
CREATE INDEX `idx_uemp_id` ON `test_db`.`indexcheck_test` (`emp_id`) USING BTREE
#
CREATE INDEX `ìdx_id_name` ON `test_db`.`indexcheck_test` (`emp_id`, `name`) USING BTREE
#
CREATE INDEX `idx_id_hdate` ON `test_db`.`indexcheck_test` (`emp_id`, `hire_date`) USING BTREE
#
CREATE INDEX `idx_id_bday` ON `test_db`.`indexcheck_test` (`emp_id`, `birthday`) USING BTREE

权限

需要对mysql数据库的SELECT权限,以及被检查数据库表的SELECT权限。

小技巧

可以使用-d选项来生成删除索引的SQL 语句。

--stats可以单独使用或与--best、--worst选项一起使用,来显示对索引的统计信息。

使用--show-indexes选项来显示每个表的索引。


打赏
赞(0) 打赏
未经允许不得转载:同乐学堂 » 找出MySQL使用率不高以及重复的索引

特别的技术,给特别的你!

联系QQ:1071235258QQ群:710045715

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续给力更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫打赏

微信扫一扫打赏

error: Sorry,暂时内容不可复制!