同事反应这个查询“较慢”,并且没有走索引:
select * from pl_georoute where STATEFLAG = 0 and ROUTE_TYPE = '9102';
经分析,这是一个400万的表:
select count(*) from pl_georoute;
4473003
以上查询结果集达到50万:
select count(*) from pl_georoute where STATEFLAG = 0 and ROUTE_TYPE = '9102';
508381
于是想到了,根据oracle对于SQL执行计划基于成本的优化原则,这么大的结果集,相对于400万的表来讲,索引不如全表扫描快。
之所以反应慢,估计是结果太大,加上网络传输等其他环节,因此在应用看来“较慢”。
以下做验证。
对于相对较大的结果集,尽管建立了相应的索引,但是oracle可以“任性的无视”。 SQLPLUS> explain plan for select * from pl_georoute where STATEFLAG = 0 and ROUTE_TYPE = '9102'; Explained. SQLPLUS> select * from table(dbms_xplan.display); --------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 472K| 195M| 55636 (1)| 00:11:08 | |* 1 | TABLE ACCESS FULL| PL_GEOROUTE | 472K| 195M| 55636 (1)| 00:11:08 | --------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("ROUTE_TYPE"=U'9102' AND "STATEFLAG"=0) 而对于可选择性【selectivity】较好的查询,oracle会乖乖的重视这个索引。 SQLPLUS> explain plan for select * from pl_georoute where STATEFLAG = 0 and ROUTE_TYPE = '9101'; Explained. SQLPLUS> select * from table(dbms_xplan.display); -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 788 | 334K| 96 (0)| 00:00:02 | | 1 | TABLE ACCESS BY INDEX ROWID| PL_GEOROUTE | 788 | 334K| 96 (0)| 00:00:02 | |* 2 | INDEX RANGE SCAN | R175_UNION_1 | 903 | | 5 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("ROUTE_TYPE"=U'9101' AND "STATEFLAG"=0)
文章评论
select * from pl_georoute where STATEFLAG = 0 and ROUTE_TYPE = '9101';
no rows selected
第二个查询条件结果。
关于filter和access的解读:
以上两个查询SQL语句的predicate谓词条件有区别,一个是9102,一个是9101
filter("ROUTE_TYPE"=U'9102' AND "STATEFLAG"=0)
access("ROUTE_TYPE"=U'9101' AND "STATEFLAG"=0)
filter是指:没有合适的访问路径,全表扫了,谓词条件只是起到了filter过滤作用;
access是指:找到合适的访问路径,走索引了,谓词条件起到了直接access读取作用。