我正在尝试检索这样的查询的第一行:
select tbl.a
from tbl
where tbl.code = 5
order by util_test.getPrio(tbl.id)
fetch first 1 rows only;
util_test.getPrio()返回一个我用于排序结果的整数。 因为我只对最好的结果感兴趣,所以我只获取第一行。
查询(没有'fetch first')只返回一行,但是,util_test.getPrio()包含一个dbms_output,如果我添加'fetch first 1 rows',我会看到相同的输出2次。如果我不这样做,我只会看到输出一次,就像预期的那样。
我对解决方案并不感兴趣(从性能的角度来看,我知道这很糟糕), 我只是想知道为什么?
答案 0 :(得分:4)
因为order by
发生在fetch first ... rows only
之前。否则,您将获得任何行,而不是util_test.getPrio(tbl.id)
返回的最低值的行。
换句话说,您可能有两行符合where
条件。这些都是排序的,然后是第一个。
修改强>
在Oracle中,fetch first ... rows only
在内部被重写为窗口函数。沿着这个:
SELECT *
FROM (SELECT *
, ROW_NUMBER() OVER(ORDER BY <HERE>) rn
FROM tbl
WHERE tbl.code = 5
)
WHERE rn <= 1
如果您愿意,可以尝试“旧的”Oracle appraoch,看看问题是否仍然存在。这可以使用rownum
伪列而不是窗口函数ROW_NUMBER()
:
SELECT *
FROM (SELECT *
, rownum rn
FROM tbl
WHERE tbl.code = 5
ORDER BY <HERE>
)
WHERE rn <= 1
不幸的是,上次检查时,“旧”方法仍比fetch first
更快:/
答案 1 :(得分:1)
我感谢order by
中的一个函数每次被引用时都会被调用 - 虽然这可能不是确定性函数。
我希望函数可以调用n * log(n)次,其中n
是查询其余部分返回的行数。
使用子查询很容易解决这个问题:
select a
from (select tbl.a, util_test.getPrio(tbl.id) as pri
from tbl
where tbl.code = 5
) t
order by pri
fetch first 1 rows only;
请注意,这将在子查询生成的每行中调用一次函数。