select * from Schem.Customer
where cust='20' and cust_id >= '890127'
and rownum between 1 and 2 order by cust, cust_id;
执行时间约为2分10秒
select * from Schem.Customer where cust='20'
and cust_id >= '890127'
order by cust, cust_id fetch first 2 rows only ;
执行时间appr 00.069 ms
执行时间差别很大,但结果是一样的。我的团队后来没有采用。不要问为什么。
那么Rownum和fetch前两行之间的区别是什么?我该怎么做才能改进或说服任何人采用。
DBMS:DB2 LUW
答案 0 :(得分:1)
尽管两个SQL最终都给出相同的结果集,但这仅在您的数据上发生。结果集很有可能会有所不同。让我解释一下原因。
为了简化理解,我将简化您的SQL:
SELECT * FROM customer
WHERE ROWNUM BETWEEN 1 AND 2;
在此SQL中,只需要第一行和第二行。没关系。 DB2将优化您的查询,并且永远不会查找第二个以后的行。因为只有前两行符合条件您的查询。
然后添加ORDER BY
子句:
SELECT * FROM customer
WHERE ROWNUM BETWEEN 1 AND 2;
ORDER BY cust, cust_id;
在这种情况下,DB2首先获取2行,然后按cust和cust_id对其进行排序。然后发送给客户(您)。到目前为止,一切都很好。但是,如果要先按cust和cust_id排序,然后再要求前2行怎么办?它们之间有很大的区别。
这是此情况下的简化SQL:
SELECT * FROM customer
ORDER BY cust, cust_id
FETCH FIRST 2 ROWS ONLY;
在此SQL中,所有行都符合查询条件,因此DB2获取所有行,然后对它们进行排序,然后将前2行发送给客户端。
在您的情况下,两个查询都给出相同的结果,因为前两行已按cust和cust_id进行排序。但是,如果前两行具有不同的cust和cust_id值,将无法正常工作。
有关此提示,FETCH FIRST n ROWS
是在 之后排序的,这意味着DB2对结果进行排序,然后检索前n行。
答案 1 :(得分:1)
此处的最佳答案: https://blog.dbi-services.com/oracle-rownum-vs-rownumber-and-12c-fetch-first/
现在选择索引范围扫描,并选择正确的基数。 那么哪种解决方案是最好的呢?我更喜欢row_number(),原因如下: 我喜欢解析函数。它们具有更大的可能性,例如将限制设置为总行数的百分比。 rownum的11g文档说: ROW_NUMBER内置的SQL函数为排序查询结果提供了出色的支持 12c允许将ANSI语法ORDER BY…FETCH FIRST…ROWS ON转换为row_number()谓词 rownum的12c文档增加了: SELECT语句的row_limiting_clause提供了出色的支持 rownum也有first_rows_n个问题
PLAN_TABLE_OUTPUT
SQL_ID 49m5a3f33cmd0, child number 0
-------------------------------------
select /*+ FIRST_ROWS(10) */ * from test where contract_id=500
order by start_validity fetch first 10 rows only
Plan hash value: 1912639229
--------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | Buffers |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 10 | 15 |
|* 1 | VIEW | | 1 | 10 | 10 | 15 |
|* 2 | WINDOW NOSORT STOPKEY | | 1 | 10 | 10 | 15 |
| 3 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 10 | 11 | 15 |
|* 4 | INDEX RANGE SCAN | TEST_PK | 1 | | 11 | 4 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber" <=10)
2 - filter(ROW_NUMBER() OVER ( ORDER BY "TEST"."START_VALIDITY") <=10 )
4 - access("CONTRACT_ID"=500)