rownum / fetch前n行

时间:2017-11-27 22:14:10

标签: sql db2 db2-luw

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

2 个答案:

答案 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)