以下问题:
两张桌子T1和T2。两个表都连接在一起,结果按T1.A,T2.A,T1.B排序。结果包含> 10Mio条目。只需要前10行的结果。
因为我们有一个命令oracle将命令一切然后将开始呈现结果。这是无效的。
通过T2.A删除排序并使用特殊索引(T1.A,T1.B,T1.C,T1.D)进行测试,其中T1.C和T1.D是where子句的一部分。这会产生奇迹,oracle根本不使用排序,但需要通过提示强制使用索引。 (不幸的是)。
下一个想法是将T1的部分结果按T1排序.A最初使用特殊索引(T1.A,T1.C,T1.D),之后让Oracle完成其工作。由于Oracle提取的结果已经被T1排序了。问题是Oralce是否只需要读取前x个条目(直到遇到新的T1.A值)才能显示第一个结果,从而节省大量查询,或者不是智能并仍然对每个潜在的结果进行排序,即使它的结果已经被T1.A正确地部分排序了?我甚至认为,如果我能正确记住它的用例,那么T1.A的小组可能会有所帮助。
是否有其他信息或最多可以验证这是否有效?任何提示都会很棒。
[更新]
一些伪代码:
SELECT Person.Name,Person.Amount FROM Person,Income WHERE Person.Name = Income.Name Ordered By Person.Name,Income.Amount,Person.Position
我们想列出前10个人,然后跳过其余的人。目前,Oracle选择所有结果,对其进行排序并返回。那是没有效果的。由于这是问题的简化版本,因此可能看起来很明显。例如,我们让Oracle选择了cartesien产品。我确实尝试了第一个索引提示。
但是我们没有组合索引(sort语句跨越多个索引)。物化视图是遥不可及的,因为我们有一个遗留的第三方代码,我们不想为每个让我们说100个查询的问题创建预先显示的视图。我们需要一个解决方案来部分重写请求或添加提示/索引等。
所以我的想法是知道Oracle是否看到了这个:
SELECT Person.Name,Person.Amount FROM(SELECT Person.Name,Person.Position FROM Person ORDER BY Person.Name),收入WHERE Person.Name = Income.Name ORDER BY Person.Name,Income.Amount,Person .Position
为了计算前20个结果,它足够聪明,只收集具有相同名称的人并按收入对其进行排序,因为这些人已经按姓名排序。因此,为了计算具有相同名称的第一批(人数),它只检索具有该名称的人(已经预先排序),直到它发现具有不同名称的人 - 因此Oracle可以确保知道具有特定名称的所有人名称。
这是我试图解决的问题。
感谢。
答案 0 :(得分:1)
我能够在类似于你的查询中模拟第一行的快速响应时间的唯一方法是在连接的每一侧添加和索引关键字段。
在您的示例中,这意味着:
这样,Oracle就有可能避免对已完成的连接进行冗长的SORT操作,因为所有连接的内容都已经预先排序。
避免添加不在索引中的其他列甚至是*,因为它会降低优化程序单独使用索引的可能性。如果是这种情况,提示可能会被忽略。
编辑=>
我添加了以下索引:
create index oe.ORDERS_IX_7 on oe.orders (order_id,order_mode)
create index oe.ORDERS_ITEMS_IX_7 on oe.order_items (order_id,unit_price)
并尝试过:
select oe.orders.order_id,oe.orders.order_mode
from oe.order_items,oe.orders
where orders.order_id = order_items.order_id
order by oe.order_items.order_id,order_items.unit_price,oe.orders.order_mode
执行计划看起来像
SORT
HASH JOIN
INDEX FULL SCAN ORDER_ITEMS_IX_7
INDEX FULL SCAN ORDER_IX_7
然后我尝试了:
select o.order_id,o.order_mode, i.unit_price
from
(SELECT order_id, unit_price FROM oe.order_items order by order_id, unit_price) i,
(select order_id, order_mode from oe.orders order by order_id,order_mode) o
where O.order_id = i.order_id
MERGE JOIN
INDEX FULL SCAN ORDERS_IX_7
SORT (JOIN)
INDEX FULL SCAN ORDER_ITEMS_IX_7
我没有足够的音量来测试这一点,但根据执行计划,两者都会比现在通过全表扫描进行排序操作的速度快得多。为简单起见,如果性能相当,我宁愿选择第一个选项。
答案 1 :(得分:0)
您应该尝试FIRST_ROWS提示 - 如果优化器知道您只想要前10行,它将相应地优化索引访问。
另一个选项是PLSQL - 您可以在已排序的SELECTS上打开游标,只检索匹配的行。
但是使用最新的统计数据,如果正确制定,这甚至可以与原始查询一起使用。但是如果没有向我们展示代码,我们可以猜测。
答案 2 :(得分:0)
在Oracle 11g中测试后,其中一个表中的行数为10,将性能提高了一倍。同时使用其中一个表的order by对成本没有影响。
SELECT Person1.Name, Person1.Amount
FROM (select * from (SELECT Person.Name, Person.Position
FROM Person ORDER BY Person.Name)
where rownum <=10) Person1, Income
WHERE Income.Name=Person1.Name
ORDER BY Person1.Name, Income.Amount, Person1.Position
解释三个案例的计划
1)原始选择 link here
2)按照一个表格的顺序选择 link here
3)限制后选择以选择一个表的10行 link here
答案 3 :(得分:0)
最后,事实证明Oracle无法做到这一点。我希望Oracle知道并重视某些排序oders和信息,但它不够聪明(至少看起来如此)。
再次总结,以便每个人都能理解:
您有以下结果集:
A | B | C (attributes)
1 | 1 | 3
1 | 3 | 3
1 | 4 | 1
1 | 1 | 2
2 | 1 | 1
...
正如您所看到的那样,逻辑结果集被alread排序为A(这就是我通过提示告诉Oracle或使用带有order by的子选择)。另外一个有能力的优化器应该知道它可以至少预先分配A,因为它来自单个表。
既然已经对A进行了排序,要返回第一行(在本例中甚至更多),所有Oracle必须对ORDER BY A执行,B,C是读取条目1到4对它们进行排序并且它不需要由于A的值发生变化,因此访问和考虑条目5是显而易见的。因此,回答前四个结果条目并不是很好。这样oracle永远不需要访问比这更多的信息。
这就是我期望计算完成的方式。即使我提示Oracle应该只准备10个条目,它仍然会读取一百万个测试记录以找到第一个x记录。这是一个我记得在2008年进行过调查的问题,现在还没有......我很失望。
我对某个程序的几乎所有性能问题都集中在跨越多个表的排序上。
记住常用的Web / Rest接口做什么...它过滤,排序并显示前x个条目(或分页)。那么为什么Oracle在这里浪费时间呢?我谈到访问百万条目而不是前500条(我的实时数据问题)。这没有意义。
非常感谢你的负担。谢谢大家。让我们希望Oracle能够在以后的版本中使用它。
希望PostgreSQL能够正确地做到这一点......