首先我们在日志文件中查到下面语句的执行比较慢超过秒了
# Query_time: Lock_time: Rows_sent: Rows_examined:
select * from TSK_TASK WHERE STATUS_ID = and MON_TIME >= and MON_TIME < ;
原来在条记录中要查出符合条件的条记录那当然慢了赶紧用EXPLAIN语句看一下索引使用情况吧
+++++
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+++++
| | SIMPLE | TSK_TASK | ref | FK_task_status_id_TO_SYS_HIER_INFOTSK_TASK_KEY_MON_TIME | FK_task_status_id_TO_SYS_HIER_INFO | | const | | Using where |
+++++
可以看出有两个索引可用FK_task_status_id_TO_SYS_HIER_INFOTSK_TASK_KEY_MON_TIME而最终执行语句时采用了STATUS_ID上的外键索引
再看一下TSK_TASK表的索引情况吧
++
| Table | Key_name | Column_name | Cardinality |
+++
| TSK_TASK | PRIMARY | ID | |
| TSK_TASK | FK_task_status_id_TO_SYS_HIER_INFO | STATUS_ID | |
| TSK_TASK | TSK_TASK_KEY_MON_TIME | MON_TIME | |
++
在Oracle或其他关系数据库下WHERE条件中的字段顺序对索引的选择起着很重要的作用我们调整一下字段顺序把STATUS_ID放在后面再EXPLAIN一下
EXPLAIN select * from TSK_TASK WHERE MON_TIME >= and MON_TIME < and STATUS_ID = ;
但是没什么效果MySQL还是选用系统建立的STATUS_ID外键索引
仔细分析一下看来Cardinality属性(即索引中的唯一值的个数)对索引的选择起了极其重要的作用MySQL选择了索引值唯一值个数小的那个索引作为整条语句的索引
针对这条语句如果使用FK_task_status_id_TO_SYS_HIER_INFO做索引而TSK_TASK表中存放很多天数据的话那扫描的记录数会很多速度较慢可以有以下几个优化方案
如果一天的任务数不多的话我们删除索引FK_task_status_id_TO_SYS_HIER_INFO那MySQL会使用索引TSK_TASK_KEY_MON_TIME然后在该天的数据中在扫描STATUS_ID为的记录那速度也不慢
如果一天的任务数多的话我们需删除索引FK_task_status_id_TO_SYS_HIER_INFO和TSK_TASK_KEY_MON_TIME然后再建立STATUS_IDMON_TIME的联合索引这样效率肯定会很高
因此建议对那些记录数多的表建议不要使用外键以避免造成性能效率的严重降低
尽量控制每张表的记录数
当一张表的记录数很大时管理和维护就会很麻烦如索引维护就会占用很长时间从而会给系统的正常运行造成很大的干扰
对随时间推移数据量不断增长的表我们可以根据时间来区分实时数据和历史数据可以使用后台服务程序定期移动实时表中的数据到历史表中从而控制实时表的 记录数提高查询和操作效率但注意每次移动的时间要足够短不要影响正常程序的数据写入如果占用时间太长可能会造成死锁问题
数据散列(partition)策略
当客户数达到一定规模后单个数据库将无法支撑更高的并发访问此时可以考虑把客户数据散列(partition)到多个数据库中以分担负载提高系统的整体性能与效率
[] []