全部产品
云市场

Limit-k

更新时间:2019-09-18 13:13:47

Limit-k 是一个只获取K行的算子,在Oceanbase中, Limit-k允许从指定偏移量(offset)开始获取K行数据,Limit语句的形式如下
Limit offset, k。Limit-k通常会跟排序语句(order by)一起使用来获取Top-k行。当order by和Limit一起出现的时候,取决于代价模型,order by算子可能会被转化成top-k sort排序。下图展示了当出现Limit-k语句的时候,order by算子被转化成Top-k排序的例子。

  1. OceanBase (root@test)> create table t1(a int primary key, b int, c int);
  2. Query OK, 0 rows affected (0.14 sec)
  3. --limit-k中的sort被转化成了top-k排序
  4. OceanBase (root@test)> explain select * from t1 order by b limit 0, 10;
  5. | =====================================
  6. |ID|OPERATOR |NAME|EST. ROWS|COST|
  7. -------------------------------------
  8. |0 |LIMIT | |10 |1151|
  9. |1 | TOP-N SORT | |10 |1149|
  10. |2 | TABLE SCAN|t1 |1000 |455 |
  11. =====================================
  12. Outputs & filters:
  13. -------------------------------------
  14. 0 - output([t1.a], [t1.b], [t1.c]), filter(nil), limit(10), offset(0)
  15. 1 - output([t1.a], [t1.b], [t1.c]), filter(nil), sort_keys([t1.b, ASC]), topn(10 + 0)
  16. 2 - output([t1.a], [t1.b], [t1.c]), filter(nil),
  17. access([t1.a], [t1.b], [t1.c]), partitions(p0)

Oceanbase中的limit-k语句在一些特定的情况下会被直接下压到存储层。下图展示了一个这样的例子,因为a是主键,所以排序算子会被消除,所以整个limit算子会被下压到存储层。

  1. OceanBase (root@test)> create table t1(a int primary key, b int, c int);
  2. Query OK, 0 rows affected (0.14 sec)
  3. OceanBase (root@test)> explain select * from t1 order by a limit 100, 10;
  4. | ===================================
  5. |ID|OPERATOR |NAME|EST. ROWS|COST|
  6. -----------------------------------
  7. |0 |TABLE SCAN|t1 |10 |59 |
  8. ===================================
  9. Outputs & filters:
  10. -------------------------------------
  11. 0 - output([t1.a], [t1.b], [t1.c]), filter(nil),
  12. access([t1.a], [t1.b], [t1.c]), partitions(p0),
  13. limit(10), offset(100)

Limit-k语句的性能在很多情况下取决于数据分布,考虑如下的一个例子: 假设t1中有100w行数据,满足b=1的行数有1w行(如果满足b=1的不到100行,那么查询需要全表扫描才能找到所有数据),那么下面这个查询的性能有如下两个极端情况:

  1. 在最好的情况下,如果主表扫描出来的前面100行数据全部满足条件,那么该查询只需要顺序扫描100行。

  2. 在最差的情况下,如果满足条件的1w行都在最后面,那么该查询需要顺序扫描99w+额外读取满足条件的100行。

  1. OceanBase (root@test)> create table t1(a int primary key, b int, c int);
  2. Query OK, 0 rows affected (0.14 sec)
  3. OceanBase (root@test)> explain select * from t1 where b = 1 limit 100;
  4. | ===================================
  5. |ID|OPERATOR |NAME|EST. ROWS|COST|
  6. -----------------------------------
  7. |0 |TABLE SCAN|t1 |2 |622 |
  8. ===================================
  9. Outputs & filters:
  10. -------------------------------------
  11. 0 - output([t1.a], [t1.b], [t1.c]), filter([t1.b = 1]),
  12. access([t1.b], [t1.a], [t1.c]), partitions(p0),
  13. limit(100), offset(nil)

在这种情况下,Limit-k的语句的性能会取决于数据分布,所以一定要谨慎的使用Limit-k语句。