在使用带有聚合函数的SQL查询时,我遇到了一些性能问题,所以我认为理解索引创建的工作原理是个好主意。我遇到了一件我无法理解的事情:这两个创建指令有什么区别?:
1.)CREATE INDEX FIELD1_INDEX ON TABLE1 (FIELD1) ONLINE TABLESPACE XXX;
CREATE INDEX timeofrequest_INDEX ON TABLE1 (timeofrequest) ONLINE TABLESPACE XXX;
2.)CREATE INDEX COMBINED_INDEX ON TABLE1 (FIELD1, FIELD2) ONLINE TABLESPACE XXX;
我问的原因是我有一个类似的查询:
SELECT SUM(field1) FROM table1 WHERE timeofrequest BETWEEN 1 AND 2;
Table1包含大量数据,因此此查询需要超过20秒才能准备好。为了避免长时间运行,我尝试使用方法1,并为每个受影响的字段创建索引。实际上,它仍然太慢。通过分析执行计划,我发现使用了timeofrequest
索引,但没有使用field1
的索引。如果我用单个语句创建组合的语句会有帮助吗?它有什么不同吗?
答案 0 :(得分:0)
因此,前两个索引与第三个索引的不同之处在于前两个索引仅使用SINGLE列作为索引。您的第三个索引由索引的两个不同列组成,但即使您只提供索引中列出的第一列,第三个索引也可以继续使用...这称为复合索引。 Oracle实际上只能在单个查询语句中使用SINGLE索引,而CBO将找出最佳选择。
在第一个示例中,您有针对各个列的两个索引。您的第二个示例是具有两列的SINGLE索引。您的第一个示例将仅使用其中一个,但不能同时使用任何给定的单个选择语句(CBO将根据您的查询决定使用什么......)。
示例:
SELECT SUM(field1) FROM table1 WHERE timeofrequest BETWEEN 1 AND 2;
这只会尝试使用您针对timeofrequest放置的索引。实际上它会尝试进行范围扫描。
第二个索引的示例:
SELECT SUM(field1) FROM table1 WHERE FIELD1 = 'x';
假设您没有仅针对'FIELD1'的INDEX,这将使用您所拥有的COMBINED_INDEX,并根据索引的第一个字段获取所有记录。
如果你有:
SELECT SUM(field1) FROM table1 WHERE FIELD2 = 'y';
这不会使用combined_index,因为索引首先使用FIELD1构建,然后使用FIELD2。
如果你有:
SELECT SUM(field1) FROM table1 WHERE FIELD1 = 'x' and FIELD2 = 'y';
这仍然会使用COMBINED_INDEX,但是在这里您可以提供更精细的粒度级别。它将利用完整索引(field1和field2 ...)更快地返回您的行。为什么这有用?好吧,你可能在FIELD1上有一个索引,只需在ON1上搜索field1仍然会产生数千(或数万或数百万......)的记录,因此能够提供另一列作为索引的一部分将简单地帮助定位您需要的记录......这反过来提供更高的选择性。
重要提示!请记住,CBO会找出最佳方法。如果你的桌子上的那个列的基数很差(研究表基数...),你甚至可能根本不使用索引,根据CBO,全表扫描会更好。如果你有很高的基数并且你还没有使用索引,那么你可能需要分析你的表及其上的索引,然后重新运行你的解释计划,看看你是否得到了新的结果。由于表中的大量数据发生变化,而且最近没有对其进行分析,因此您可能也可能具有较低的基数。分析你的表/索引是一件非常重要的事情,很容易被忽视。在很多场合,我发现我工作的实例只是重新分析表格和/或索引做了不可思议的改进。
请查看分析表并使用DBMS_STATS。
https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_stats.htm
另一个解决方案是,如果您有大量数据,并且您的“请求时间”列实际上只有一小组不同的值(可能在您的5000万条记录表中,只有20个不同的值......) ,那么您可以选择设置分区表并从那里提供索引。它将大大提高查询性能时间。