个人总结几点:
1、驱动表中的索引要将区间字段(sendtime之类)放到固定值(orgid等)的后面
2、驱动表的连接字段可以放在索引最后,以避免读取rowid
3、连接表的连接字段要放在索引最前面。
举个例子:
selectcount(*)as col_0_0_
fromREC_BANKINSTRUCTION batchrecba0_
crossjoinREC_BILL_DETAIL batchrecbi1_
wherebatchrecbi1_.ID = batchrecba0_.BILLDETAILID
andbatchrecba0_.ORGID = batchrecbi1_.ORGID
andbatchrecba0_.STATUS = :1
andbatchrecba0_.ORGID = :2
andbatchrecba0_.SENDTIME >= :3
执行计划:
现有索引结构:
索引优化:
dropindexREC_BANK_QUERY_INDEX;
createindexREC_BANK_QUERY_INDEX onREC_BANKINSTRUCTION(ORGID,SENDTIME,CREATETIME, STATUS, BILLDETAILID);
dropindexREC_BILL_ORGID;
createindexREC_BILL_ORGID onREC_BILL_DETAIL(ORGID,IMPORTDATE,ID);
优化之后执行计划:
优化之后索引结构:
以上并没有考虑索引字段的顺序问题
但是,sql是从REC_BANKINSTRUCTION loop到REC_BILL_DETAIL
所以,首先应确定REC_BANKINSTRUCTION的索引,应该是status\orgid\sendtime三个字段,然后把billdetailid包含进来
第一个索引存在两个问题:
1、sendtime应该往后放,这样索引数据将会聚集,减少io。如果sendtime往前放,那么status不是索引,而是筛选,io增大
建议顺序为orgid\status\sendtime,至于createtime可以放着,是用于筛选的,当前没有用到
2、REC_BILL_DETAIL是通过orgid\id关联的,那么这两个字段必须放前面,如你现在索引,则ID变成了筛选,而非索引
建议顺序orgid\id\importdate,importdate是包含字段,可以用于筛选,可以用于显示
因此,先对REC_BILL_DETAIL的索引顺序更改:
dropindexREC_BILL_ORGID;
createindexREC_BILL_ORGID onREC_BILL_DETAIL(ORGID,ID,IMPORTDATE);
更改后索引为:
执行计划为:
可以看到对REC_BILL_DETAIL的join查询有了明显提高。
再更新REC_BANKINSTRUCTION表的索引:
dropindexREC_BANK_QUERY_INDEX;
createindexREC_BANK_QUERY_INDEX onREC_BANKINSTRUCTION(ORGID,STATUS,SENDTIME, CREATETIME, BILLDETAILID);
索引为:
执行计划为:
Instruction表的扫描有了明显提高。