尝试连接2个表时,我的性能非常慢:一个有39M行,另一个有10k(35秒)。这在Azure SQL Premium实例上运行,这是非常不错的服务器
select m39.*
from [Table_With_39M_Rows] m39
inner join [Table_With_10K_Rows] k10 on m39.[Id] = k10.[Id]
甚至一个count(*)
需要大约10秒钟
select count(*)
from [Table_With_39M_Rows] m39
inner join [Table_With_10K_Rows] k10 on m39.[Id] = k10.[Id]
以下是表格详细信息:
[Table_With_39M_Rows]
有大约3900万行(50列)和一个聚簇列存储索引:
CREATE CLUSTERED COLUMNSTORE INDEX CCI_Table_With_39M_Rows
ON Table_With_39M_Rows
CREATE UNIQUE NONCLUSTERED UNCI_Table_With_39M_Rows_Id (Id ASC)
[Table_With_10K_Rows]
有大约10k行(50列)和Id
作为主键
ALTER TABLE Table_With_10K_Rows
ADD CONSTRAINT PK_Table_With_10K_Rows
PRIMARY KEY CLUSTERED([Id] ASC)
Clustered Columnstore索引扫描占用99%并减慢所有内容。
如何优化此特定连接?我应该采用什么索引策略?
如果行组消除有效(您可以认为这跳过了不满足谓词的整个行段)并且查询本质上是分析性的,则群集列存储索引是有用的。
要检查是否正在执行段删除,您可以使用以下查询
下面是我所拥有的查询的示例演示(因为我们没有您的测试数据),这可能有助于您了解更多信息
查询:
select s.* from sales s
join
numbers n
on n.number=s.id
数字表只有65356行,销售表有超过300万行。每个段只能有一百万行。如果你能观察到statistics IO
的输出,SQLSERVER读取2段(200万行),跳过2段,是不是很好,我希望只读取一个段,剩下三个段要跳过。但是如下所示,读取2
Table 'sales'. Segment reads 2, segment skipped 2.
发生这种情况是因为您可能已经从堆创建了集群列存储,因此请尝试执行以下操作
删除现有的聚簇列存储索引,就我而言
drop index nci on sales
现在尝试先创建聚簇索引,然后再创建聚簇列存储,这有助于sqlserver将行按顺序插入到聚簇列存储索引中。您可能还希望使用maxdop 1来避免并行和无序行
create clustered index nci on sales(id)
create clustered columnstore index nci on sales
with (drop_existing=on,maxdop =1)
如果您现在运行查询,您可以看到发生段消除并且查询速度很快
Table 'sales'. Segment reads 1, segment skipped 2.
参考文献和进一步阅读: https://www.sqlpassion.at/archive/2017/01/30/columnstore-segment-elimination/ https://blogs.msdn.microsoft.com/sqlserverstorageengine/2016/07 / 17 / columnstore-index-how-do-they-defer-from-traditional-btree-indices-on-rowstore-tables / https://blogs.msdn.microsoft.com/sql_server_team/columnstore-index-performance-rowgroup-elimination/
我建议你在使用[]时保持一致。
外键的ID不是一个好名字。
列存储索引为使用全表扫描的查询提供了高性能增益,并且不适合搜索数据的查询,搜索特定值。
仅仅因为你需要将columnstore用于其他目的并不能使它成为一个很好的应用程序。
在[Table_With_39M_Rows]上尝试常规非聚簇索引。[ID]