6

我有一个大约 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

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

Erp_In_failed:

corr_id
interface
error (clob)   
input (clob)

带有索引(corr_id 和接口)

我要优化的查询很简单:

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 万行的简单表,order by 需要几秒钟,有什么区别?100 万是否足以在 RAM 中对其进行排序?

谢谢,

4

5 回答 5

4

您正在对 500 万行进行排序,其中包括大约 10 万个 clob。您不太可能在内存中做到这一点。如果您在带有统计信息的 SQL*Plus 中运行查询,您应该会看到查询大量写入磁盘。

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

建立一个复合索引erp_in(indate desc, corr_id, interface)也会有所帮助,因为驱动表的结果将被预先排序,因此排序应该花费更少的工作。INDATE 分区可能有类似的效果,但分区是企业版的额外收费,因此不是一个便宜的修复(获取更多内存可能会便宜很多)。

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

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


“所以我应该按日期分区吗?如果不在 INDATE 字段上添加 WHERE 子句会有所帮助”

这取决于。分区引入了表的一些物理组织,因此行将(至少)需要较少的排序。少多少取决于分区的粒度:按一天的范围进行分区,并且表几乎已经处于 INDATE 顺序,按一年的范围进行分区,而且情况要少得多。

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

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

于 2012-11-01T09:49:21.517 回答
1

您真的要向 Web 服务器获取这么多行吗?如果是,请检查您的代码以缩小到所需的范围。

  1. 尝试根据日期时间将旧数据归档到另一个表。仅在需要时重新编写逻辑以获取较旧的数据。
  2. 正如其他人所提到的,在大多数情况下,索引/键应该会有所帮助

如果您不能执行上述任何操作,另一个丑陋的解决方案(不确定它是否会变得更糟)是创建内存表,过滤并获取所需的内容,然后获取 CLOB 数据。

于 2012-11-01T13:27:28.960 回答
0

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

于 2012-11-01T09:05:21.220 回答
0

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

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

例如仅获取最后两天:

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;
于 2012-11-01T09:42:32.343 回答
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 秒。

我发现该链接对此非常有帮助。

于 2017-02-22T12:19:23.403 回答