数据库作为一个大型的并发存储系统,其内部设计极其复杂,开发者在使用数据库时,面临着可用性、可靠性、性能、安全、扩展性等多重挑战,这就使得数据库的使用具有较高的技术门槛。一般大型团队都会雇佣专职的DBA来维护数据库的日常运行,指导开发者建立正确的使用姿势,但是对于一般的中小型团队,受限于人力成本,这种模式难以实现。随着DevOps理念的流行,开发者开始更多的参与和承担数据库的运维工作,其中就包括对数据库的定期巡检。
对数据库定期进行健康检查是数据库日常维护的重要环节,通过检查数据库的各项运行指标,评估系统的运行风险,提前将风险消灭在摇篮中,能够有效提高数据库服务的质量,今天我们就来聊聊开发者如何对数据库进行健康检查。
数据库的健康检查涉及索引设计、容量规划、服务安全、参数配置、用户访问、集群复制6个方面。
索引设计
合理的索引设计能够有效加速数据库的访问,提高查询的执行效率,减少用户查询对服务端的资源消耗。但是不合理的、低效的、冗余的甚至无效的索引不仅无法起到加速查询的效果,反而会影响数据库的插入、更新性能,甚至是数据库的高可用方案能否生效。
- 主键索引缺失: 由于MySQL默认存储引擎InnoDB(MySQL 5.6版本 以上)使用的是聚簇索引表设计,这就要求所有的表必须包含一个主键,所有的数据记录按照主键次序构建B+树。如果用户在创建表时显式指定主键,则数据库会使用用户指定的主键构建B+树,但是如果用户没有显式指定主键,同时也没有创建任何唯一键索引,InnoDB为了确保每张表至少包含一个主键,则默认会为用户生成一个“隐含主键”,该主键对用户不可见,甚至对于MySQL Server层的binlog也不可见。binlog是连接MySQL主从复制节点的纽带,所有主节点的更新都是通过binlog传递给从节点的,一旦binlog中没有更新记录的主键ID,这就会导致基于Row格式的binlog在从节点执行时,无法唯一确定一条记录,只能通过全表扫描来进行匹配,大幅降低了从机的执行效率,造成复制延迟。如果是高可用故障切换的从节点,会导致切换的时间大幅增加,甚至会导致高可用机制失效。如果是实现读写分离的只读从节点,则会导致应用读到的数据可能是很久以前的旧数据。所以我们建议使用InnoDB存储引擎的MySQL用户在创建表时,必须显式指定主键。
- 主键索引与业务相关:如果用户在创建表时指定的主键与业务相关,可能会被频繁的更新,这样会引起MySQL数据库的InnoDB存储引擎进行频繁的节点合并和分裂,造成大量额外的系统IO开销,影响数据库的插入和更新性能。我们推荐开发者在创建表时指定与业务无关的自增字段作为主键,这样不仅会提高按时间序插入的性能(顺序写入硬盘),同时也可以提高按插入时间范围检索的查询效率。
- 冗余索引:如果一个索引涉及的字段属性包含另外一个索引涉及的字段属性,同时两个索引字段顺序一致,且两个索引的首字段属性相同,则可以认为涉及字段少的索引为冗余索引。在MySQL 5.7推出sys库之前,我们可以通过percona的工具pt-duplicate-key-checker来完成对冗余索引的检查,在MySQL 5.7中,我们可以通过sys库schema_redundant_indexes表来完成。
- 低效索引:索引的作用在于通过索引,查询能够扫描更少的记录。数据库中的记录在索引字段区分度越高,扫描的记录数就越少,执行的效率就越高。如果数据库表中的记录在索引字段区分度不大,索引对记录的筛选结果就不明显,索引就无法起到加速查询的作用。通过数据库记录在索引字段的区分度,我们可以衡量索引的执行效率。MySQL系统库mysql库下,innodb_index_stats表的stat_value字段,记录了某张表在某个索引的不同取值的记录个数,innodb_table_stats表的n_rows字段记录了某张表的总记录数,二者相除,即可得到数据库记录在某个索引的区分度,越接近1,表示区分度越高,低于0.1,则说明区分度较差,开发者应该重新评估SQL语句涉及的字段,选择区分度高的多个字段创建索引,通过运行下面的SQL语句,就可以计算每张表的索引区分度。