基础算法
数据库
Javascript
HTML 编程
SVG
附录
这篇文章承接上文 MySQL 分区表性能测试。本来想着通过分区表来解决大数据量场景下(千万级)有可能的慢查询问题,实际证明只要索引建好,5000 万查询性能也没有多少影响。但是在 Keeper 调度工具中,任务实例表是非常关键的表,又是查询非常多的表,且查询方式多样。不改分区,为了应对将来有可能发生的查询问题,又不能什么都不做。
主要优化思路如下:
通过全局查找,涉及到两个项目。与任务实例表qross_tasks
相关的查询共有169
个,涉及到字段共9
个。这次整理完了,才发现自己之前写 SQL 语句真是随心所欲。因为项目周期跨了几年,WHERE 条件中各种写法都有,很多时候都没有考虑性能问题,只是实现了逻辑就好了,觉得该建索引了,就加一个,这 9 个字段一共建了8
个索引,也没考虑索引建的合适不合适,鄙视自己一下。
与查询相关的字段有:
id
主键。job_id
调度作业 id。status
任务状态,使用最频率的字段。checked
异常任务检查。task_time
任务时间。record_time
记录时间。to_be_start_time
即将重启时间。create_time
任务创建时间。update_time
任务更新时间。不再考虑已经建好的索引是否合适,重新分析查询条件,再为这些条件重新确定怎么建索引。
id
主键基本无问题。job_id
上一篇文章测试过,基本也没什么问题。status
最可能会出问题的字段,这个字段的枚举值只有14
个,且分布非常不平衡,最多的success
应该占90%
以上,其他的有的甚至个位数。状态字段在任务运行过程中会不断变化。且80%
以上的查询与这个字段相关。checked
只有3
个值,说实话,建索引也效果不明显。嗯,这个字段占了一个索引。task_time
不会单独使用,会与其他字段一起查。record_time
不会单独使用,会与其他字段一起查。to_be_start_time
正常运行中,这个字段只在不到千分之一的数据中有值,使用率很低。它也占了一个索引。create_time
有查询用到且会使用范围查询。update_time
有查询用到且会使用范围查询。经过分析和思考,最终有了解决方案。
status
是最有可能有问题的字段,枚举值少,数据分散不均,查询频率还高。根据查询场景,作了数据冗余。把qross_tasks
表又拆出两个表qross_tasks_living
和qross_tasks_abnormal
。其中qross_tasks_living
表存储正在执行中的任务,所有与正在执行中任务状态的查询都使用这个表做处理。对执行中的任务查询反而是最频繁的,基本占60%
左右。这个表qrosss_tasks_abnormal
的数据量基本维持在十位数甚至个位数,一般很少会出现百位数。表qross_tasks_abnormal
存储所有异常任务记录,所有与异常任务状态相关的查询都使用这个表进行查询,这个表的数据量一般占总数据量的3%
以下,查询量占总查询量的20%
左右。而且,checked
字因为与异常状态完全相关,也放到这个表中,极大的提升了这个字段的查询效率。至此,80%
可能的查询问题已解决。
另一个使用率比较低的字段to_be_start_time
因为与其他字段没多少关联,在实际生产中使用也较少但是比较关键,所以也专门建了一个表qross_tasks_to_be_start
,这个数据量基本在个数位最多十位数。
id
查询基本无问题,在查询时需要把主键放在条件中的第一位。单条数据关联查询时,优先使用一次子查询而不是直接 JOIN。
job_id
经常跟其他字段一起使用,如task_time
、status
等。status
相关的去相关的表去查,另外创建job_id
+task_time
的唯一键索引。这个索引可以提高创建任务实例语句的效率。这个优化思路并不是常用的拆表或建分区的优化方式,主要还是分析查询条件、根据查询条件建立不同的冗余表。优点是可以极大的提高查询效率,缺点是数据冗余必然会增大“增删改”的复杂度。
优化后的数据表结构如下:
参考链接