根据索引列在 Oracle SQL 中查找“下 25 行”
Posted
技术标签:
【中文标题】根据索引列在 Oracle SQL 中查找“下 25 行”【英文标题】:Finding the "next 25 rows" in Oracle SQL based on an indexed column 【发布时间】:2015-12-01 21:01:28 【问题描述】:我有一个大表(约 200M 行),它在数字列 Z 上建立索引。在键列 K 上也有一个索引。
K Z
= ==========================================
1 0.6508784068583483336644518457703156855132
2 0.4078768075307567089075462518978907890789
3 0.5365440453204830852096396398565048002638
4 0.7573281573257782352853823856682368153782
我需要做的是找到“围绕”给定记录的 25 条记录。例如,从 K=3 开始的“下一个”记录将是 K=1,然后是 K=4。
我得到了几个消息来源(最著名的是佛罗里达州立大学的一些人的this paper)的领导,认为像下面这样的 SQL 应该可以工作。不难想象,沿着索引列以升序或降序扫描会很有效。
select * from (
select *
from T
where Z >= [origin's Z value]
order by Z asc
) where rownum <= 25;
理论上,这应该找到 25 个“下一个”行,类似的变体可以找到 25 个“上一个”行。但是,这可能需要几分钟,并且解释计划始终包含全表扫描。全表扫描对于我的目的来说太昂贵了,但我所做的任何事情似乎都没有提示查询优化器利用索引(当然,简短地将上面的 ">=" 更改为等号,这表明该指数存在且可操作)。我尝试了几个提示都无济于事(索引,index_asc 在几个排列中)。
我想做的事是不可能的吗?如果我试图在我有更多控制权的大型数据结构上执行此操作,我会在索引列的值和树上构建一个链表以找到正确的入口点。然后遍历列表将非常便宜(是的,我可能必须在整个磁盘上运行才能找到我正在寻找的记录,但我肯定不必扫描整个表)。
如果我正在使用的数据库运行 Oracle Database 11g 企业版 11.2.0.3.0 - 64 位,这对我的查询很重要。
【问题讨论】:
要清楚。如果您的表有 200 行1 .. 200
并且您想要最接近行 100
的 25 行,您将获得行 88 .. 112
?同样的情况。那么最接近行 5
的 25 行将是行 1 .. 25
吗?
不确定它的速度是否更好,但如果我理解正确,请尝试...WHERE something ORDER BY k ROWS BETWEEN 12 PRECEDING AND 13 FOLLOWING
@JuanCarlosOropeza 抱歉,我对边缘情况或实际感兴趣的范围不是很清楚。我真正需要的是任一方向上最接近的 25 条记录。在表格的开头和结尾,我不太担心一个方向或另一个方向的短缺。数字 25 也不是一成不变的,主要是为了调味。我认为解决问题的解决方案将适用于不同的范围。
@Mihai 我没有听说过 BETWEEN ... PRECEDING AND ... FOLLOWING 语法,但我一定会试一试。它是否适用于与磁盘上的行顺序不同的顺序?
您可以随意订购
【参考方案1】:
我构建了一个包含 10K 行的小测试用例。当我填充表格以使 Z 值已排序时,您给出的确切查询倾向于使用索引。但是当我用随机值填充它并刷新表统计信息时,它开始进行全表扫描,至少对于 n 大于 25 的某些值。所以有一个临界点,优化器决定它的工作量会做查找索引条目然后查找表中的相应行超过做全扫描的工作量。 (当然,它的估计可能是错误的,但这就是它必须继续下去的原因。)
我注意到您使用的是SELECT *
,这意味着查询将返回两列。这意味着必须访问实际的表行,因为两个索引都不包含两列。这可能会促使优化器倾向于对更大样本进行全表扫描。如果可以仅从索引中完成查询,则更有可能使用索引。
一种可能性是您根本不需要返回K
的值。如果是这样,我建议您将两个出现的SELECT *
更改为SELECT z
。在我的测试中,此更改导致执行全表扫描的查询改为使用索引扫描(并且根本不访问表本身)。
如果您确实需要在结果中包含K
,那么您可以尝试在(Z, K)
上创建索引。该索引可用于满足查询而不访问表。
【讨论】:
以上是关于根据索引列在 Oracle SQL 中查找“下 25 行”的主要内容,如果未能解决你的问题,请参考以下文章