Columnstore索引 - offset-fetch查询的性能降低

时间:2017-05-09 13:50:52

标签: sql sql-server azure-sql-database columnstore

我们在Azure数据库(高级层)上有大约35M行的Fact表,此表启用了集群列存储索引,以提高查询性能。

我们使用类似的下面代码在Fact表上进行了分页(对Elastic Search进行索引):

SELECT *
FROM [SPENDBY].[FactInvoiceDetail]
ORder by id
offset 1000000 rows fetch next 1000 rows only

但是这个查询执行速度很慢,甚至超过10分钟,它还没有完成。如果我们更改为使用TOP,它的效果非常好,大约需要30秒:

SELECT TOP 1000 * 
FROM [SPENDBY].[FactInvoiceDetail]
WHERE ID > 1000000 
ORDER BY Id

偏移量获取查询的估计执行计划:

enter image description here

我不确定我是否理解offset-fetch查询是否在群集列存储索引上执行得非常糟糕。

此表在外键上有很多非集群B树索引,在Fact表的Id上有一个唯一索引,以提高性能

此偏移量获取查询的执行计划:

https://pastebin.com/BM8MXQMg

3 个答案:

答案 0 :(得分:4)

这里有一些问题。

1) Ordering BTree index is not a covering index for the paging query.

2) The rows must be reconstructed from the CCI.

3) The offset is large.

分页查询需要在排序列上使用BTree索引来计算应返回哪些行,如果该BTree索引不包含所有请求的列,则每行需要进行行查找。这是"嵌套循环"查询计划中的运算符。

但是行存储在CCI中,这意味着每列都在一个单独的数据结构中,并且对于每一行,读取单个行需要每列一个逻辑IO。这就是为什么这个查询特别昂贵的原因。为什么CCI是分页查询的不良选择。排序列上的聚簇索引,或包含剩余请求列的订购列上的非聚集索引会更好。

这里的次要和较小的问题是大偏移量。 SQL必须跳过偏移行,计算它们。因此,这将读取BTree叶级别页面的前N页以跳过行。

答案 1 :(得分:2)

这句话:

SELECT TOP 1000 * 
FROM [SPENDBY].[FactInvoiceDetail]
WHERE ID > 1000000 
ORDER BY Id

完全适用于ID为>的(群集?)ID字段索引(是主键?)准备好1000000

另一个语句对将满足偏移量1000000行的ID值进行排序和搜索

偏移量1000000行不等于WHERE ID>优化器为1000000,除非ID值没有间隙。

答案 2 :(得分:1)

这里的主要问题是OFFSET值很大..

  

偏移1000000行仅获取下一个1000行

OFFSet和Fetch效果很好,当OFFSET值很小时,请参阅下面的示例了解更多详情

SELECT orderid, orderdate, custid, filler
FROM dbo.Orders
ORDER BY orderdate DESC, orderid DESC
OFFSET 50 ROWS FETCH NEXT 10 ROWS ONLY;

我按列排序,因为列中的键列和列都包括在内。这导致以下计划..

这里要注意的关键点是SQLServer最终读取Offset + fetch(50 + 10)行然后最后过滤10行

enter image description here

因此,使用大的偏移量,即使使用合适的索引,也将以1000000 + 1000行读取结束,这是非常巨大的

如果您可以询问,sql server会在扫描后立即过滤掉1000行,这可以帮助您进行查询..通过重写您的查询,可以可能(未针对您的架构进行测试)

WITH CLKeys AS
(
 SELECT ID
 FROM yourtable
 ORDER BY ID desc
OFFSET 500000 ROWS FETCH FIRST 10 ROWS ONLY
)
SELECT K.*, O.rest of columns 
FROM CLKeys AS K
CROSS APPLY (SELECT columns needed other than id
FROM yourtable  AS A
WHERE A.id= K.id) AS O
ORDER BY Id desc;

<强>参考文献:
http://sqlmag.com/t-sql/offsetfetch-part-1#comment-25061