通过查询优化Oracle订单

时间:2012-11-01 08:50:50

标签: sql oracle optimization query-optimization partitioning

我有一个大约有500万行的表格,如下所示:

Erp_in:

corr_id varchar(50) (almost Unique)
corr_type nvarchar(1) (4 distinct values)
interface varchar(20) (around 10 distinct values)
indate DateTime

有3个不同的索引(corr_id,interface和indate)
而且我还有另一张表,我通常会将其与原始表连接,大约有100000行

Erp_In_failed:

corr_id
interface
error (clob)   
input (clob)

索引为(corr_id和interface)

我想要优化的查询是简单的:

SELECT a.corr_id, a.interface, a.indate, b.error 
FROM erp_in a left join erp_in_failed b on a.corr_id = b.corr_id and a.interface =          b.interface
Order by a.indate desc;

如果我删除了订单,那么查询的时间并不长,但是如果不是更多的话,订购数据大约需要3分钟。

如何优化查询? 我正在考虑将旧数据分区/删除到历史表/可能创建一个序列主键,并按它或其他任何你想到的顺序......

修改
执行计划表示全表扫描,并且它不是连接需要这么长时间的顺序 即使这个查询也需要永远:

SELECT * FROM erp_in
ORDER BY indate;

我尝试过使用Paging,但这也不起作用,并且需要几分钟才能获得20个结果,也许我做错了?

如果我在indate字段上添加WHERE子句,它会使用索引,但只有当它少于20天时,除此以外的任何内容仍使用全表扫描。 (即使有40天,添加INDEX提示使查询运行得更快,但仍然不够)。

只是为了好奇,我有一个100万行的简单表,按几秒钟的顺序排序,有什么区别?是100万足以在RAM中对它进行排序吗?

谢谢,

5 个答案:

答案 0 :(得分:3)

你要排序五百万行,包括大约十万个clobs。你不太可能在记忆中做到这一点;如果你在带有统计信息的SQL * Plus中运行查询,你应该会看到写入磁盘的查询。

提高性能的一种方法是在缓冲区缓存中添加更多GB,但这可能是一个昂贵的选择而不是快速选择。

erp_in(indate desc, corr_id, interface)上构建复合索引也有帮助,因为驱动表的结果将被预先排序,因此排序应该减少工作量。通过INDATE进行分区可能会产生类似的效果,但分区对企业版来说是一个额外收费,因此不是一个便宜的修复程序(更多的内存可能会便宜很多)。

您对存档旧数据的引用表明您实际上并不想要检索所有记录。如果是这种情况,那么使用WHERE子句减小结果集的大小会有很大帮助。调整某些东西最简单的方法就是首先做不到的工作。

添加主键并按顺序排序不会减少实际排序所需的工作量。


  

“我应该按日期分区吗?如果不添加WHERE会有帮助吗?   关于INDATE字段的条款“

这取决于。分区引入了表的一些物理组织,因此行(至少)需要较少的排序。多少少取决于分区的粒度:在一天内按范围分区,表几乎已经按照INDATE顺序排列,分区的范围为一年,而且差不多。

但是,请记住,分区主要不是性能选项。它是管理数据,尤其是加载和可用性的选项。实际上,它可能会降低某些查询的性能,这些查询不符合分区键所应用的排序。

那么,你应该按日期分区吗?这不是我们可以回答的问题。回答它需要你对我们缺乏的系统有深入的了解。但是,如果您拥有许可证,那么您应该进行调查和基准测试。

答案 1 :(得分:1)

你真的在网络服务器上取这么多行吗?如果是,请查看您的代码以缩小到所需的范围。

  1. 尝试根据日期时间将旧数据存档到另一个表。重新编写逻辑以仅在需要时获取旧数据。
  2. 正如其他人所提到的,索引/密钥在大多数情况下应该有助于一英里
  3. 如果您不能执行上述任何操作,另一个丑陋的解决方案(不确定它是否会变得更糟)是创建内存表,过滤并获取所需内容然后获取CLOB数据。

答案 2 :(得分:0)

您是否尝试过其他索引?我做了类似的事情,我在indate DateTime字段上使用了聚集索引。这是在一个前提下,大多数查询将限制在一段时间内,并且B树的重新平衡不会成为问题,因为大多数插入都会增加键值。获取查询的执行计划,看看是否无法对其进行优化。

答案 3 :(得分:0)

如果在erp_in上创建复合索引(indate desc, corr_id, interface)将使用索引,查询将更快。

但是你最好找到一种方法来最小化要排序的数据的大小。

例如,只获取最近两天:

SELECT a.corr_id, a.interface, a.indate, b.error 
FROM erp_in a left join erp_in_failed b 
     on a.corr_id = b.corr_id and a.interface = b.interface
WHERE indate > trunc(sysdate - 1)
Order by a.indate desc;

答案 4 :(得分:0)

我想分享一下我的经历,我遇到了问题作者所遇到的类似问题。

我的查询很长,它包括几个表和连接,这里我只是试图用简单的查询来展示我的场景。它返回大约80,0000条记录。我发现order by是我查询中的瓶颈部分。

select column1, colum2 from table order by colum2

当我检查执行计划时,就像我的查询在column1上使用索引一样。

我刚按顺序包含了column1。

select column1, column2 from table order by column2, column1

它帮助了我,样本阅读就像改变之前需要花费8秒钟,经过上述改变只需要2秒钟。

我发现link对此很有帮助。