SQL Server—— 在ETL过程列存储索引vs 行存储索引

本文探讨了在SQL Server的不同版本中,列存储索引与行存储索引的选择及其在ETL过程中的应用。文章分析了列存储索引的发展历程,强调在资源有限、大数据查询和高度压缩需求时,列存储的优势。通过实验比较了两种存储类型的导入速度和空间效率,结论是列存储在特定ETL场景下表现更优,但最佳选择取决于具体环境和ETL流程。
摘要由CSDN通过智能技术生成

本人新书上市,请多多关照:《SQL Server On Linux运维实战 2017版从入门到精通》

在这里插入图片描述

这几天我一直在跟进公司的一个性能问题,里面涉及到聚集列存储索引的问题。跟微软的技术支持讨论了一下,他们的建议可以考虑转成非聚集的列存储索引,那我到底怎么做好呢?我觉得有必要研究一下这两者的差异,说不定可以得出一个“不用列存储索引”的结论呢。
为了感觉记录下处理过程,在本系列中先缓一下分区的内容,插播一篇关于列存储的文章。

选择列存储前需要了解的内容

  在选择之前,首先要想一下下面的问题:

  • 我们到底要不要用列存储索引?
  • 如果要用,用在哪些表上?用哪种?
  • 如果是非聚集的列存储索引,建在哪些列上?

SQL Server 2012

  在SQL 2012的时候,只有非聚集的列存储索引,同时它不允许创建后更新,所以如果选择列存储,就只有非聚集可选且只适合不怎么更新的表。这种限制使得非聚集列存储索引很难被推广。其中不允许更新的限制成了绝大部分企业不使用该功能的最重要因素,虽然可以用一些方式来实现,不过确实不够完美。

SQL Server 2014

  SQL Server 2014是一个开拓性的版本,不仅引入了内存技术(这是这个版本最大的亮点),还增强了列存储技术和其他比如AlwaysOn方面的高可用技术。在这个版本中,引入了聚集列存储索引且可更新,但是此时非聚集的列存储索引依旧是不可更新。可更新的聚集列存储索引的出现,一时间使得很多人认为DW只需要聚集的列存储所有,不过当然还没有什么技术是可以面面俱到的。

SQL Server 2016

  SQL Server 2016,列存储索引发展成3个独立的体系:

  1. 基于磁盘的聚集列存储索引:主要针对DW,基于磁盘(disk-based)是相对于基于内存而言,即从SQL 2014出现的内存技术。
  2. 基于磁盘的可更新的非聚集列存储索引:主要针对混合场景OLTP+实时报表,终于可以更新非聚集列存储了。
  3. In-Memory 聚集列存储索引:主要针对基于内存技术的混合场景。
      到了这个时候,列存储索引基本上就能应对所有常规场景了,聚集列存储索引已经可以应对绝大部分的需求,不过也还有一些场景不适合,比如索引视图,事务复制,CDC等,还有一些数据类型并不支持聚集列存储索引。

SQL Server 2017

  SQL Server 2017正式以兼容Linux和Windows平台为主要卖点来发布,针对列存储索引,2017引入了聚集列存储索引对LOBs的支持,对非持久的计算列支持。还有非聚集列存储索引对联机重建的支持。
  

Azure SQL DB

  Azure SQL DB本质上跟当前最新的数据库版本(本文发布时是SQL 2019)相同,并且由于云平台的特性,它具有更快的新功能发布,几乎所有技术都在Auzre上先运用然后才会更新到本地版。

什么时候适合用列存储索引

  首先要注意我这里没讨论用哪种,只是考虑用列存储还是行存储(也就是常规索引)。
  有几个关键因素会影响是否使用:

  1. 查询绝大部分表数据时:比如10亿数据的表,经常需要查询9亿数据,那么这个时候列存储索引会很高效。
  2. 资源比如内存/CPU/磁盘空间是查询性能的瓶颈时:因为列存储索引带有高度压缩的特性,所以对资源有大量要求的查询可以通过列存储索引的方式来减少数据集。
  3. 列里面包含大量相似的数据或者可以实现高度压缩的数据时。可以大幅度节省空间消耗。
  4. 针对ETL过程,对于归档所有数据时,聚集列存储索引可以节省大量空间。

  如果是考虑聚集列存储索引,首先要考虑是否有不支持的数据类型,其次就是单纯测试性能时,可能需要其他技术来做辅助,比如内存表。

  上面的内容也意味着如果你只需要查询少量数据或者高度唯一的数据时,列存储索引并不一定是最好的选择。

  假设我们现在确实需要用到列存储索引,那么本文打算介绍一下如何去选择。

影响导入的因素

  影响加载速度的关键因素就是尽量减少对基础结构的额外负担。说白了就是没有索引和没有压缩。但是在SQL 2014中,聚集列存储索引的Delta-Stores使用页压缩进行压缩。一开始的设计应该时为了把Delta-Stores占用的空间释放出来,但是从实践来看不见得是有效的。因为不管加载多快,都会被压缩操作拖延总体时间。
  从SQL 2016开始,对如并行插入进行了改进。特别是对于具有大量文本列的宽表。它主要的做法是移除Delta-Stores上的压缩。

实验

  说太多好像没什么意义,要不还是直接来看实验吧。首先创建一个表,然后通过循环插入100万随机数,看一下在CCITable中使用聚集列存储索引聚集及非聚集行存储索引的差异。
  下面的代码需要单独执行,按照Step来执行,在Step 4和Step 7 时打开实际执行计划,其他时候可以关闭,减少运行时间,不过不关闭也没关系。
  第一步,创建一个表,都是BIGINT类型。此时表是堆表。
  第二步,循环100万次插入随机数据。并检查表大小
  第三步,创建两个非聚集索引。并检查表大小
  第四步,打开执行计划并包含SET STATISTICS IO命令,进行全表的扫描(实际上就是索引扫描)及聚合计算。可以得到执行计划和IO信息。
  第五步,移除表上的所有索引
  第六步,创建聚集列存储索引,聚集列存储索引不需要指定列,实际上就是把整个表转换成一个列存储格式。同时检查表大小。
  第七步,按照四步的方式再次执行并查看结果。

--Step 1 Create Table
CREATE TABLE CCITable (ValueOne BIGINT, ValueTwo BIGINT, ValueDate DATETIME)

--Step 2 1 million data loading
DECLARE @rand1 BIGINT, @rand2 BIGINT, @b INT = 1

WHILE @b <= 1000000
BEGIN
 SELECT @rand1 = CAST(((RAND()*0.00001) * ABS(CHECKSUM(NEWID()))) AS BIGINT)
 SELECT @rand2 = CAST(((RAND()*0.0001) * ABS(CHECKSUM(NEWID()))) AS BIGINT)
 
 INSERT INTO CCITable VALUES (@rand1,@rand2,DATEADD(DD,-(@rand1/10),GETDATE()))
 
 SET @b = @b + 1
END
--check the table size
SELECT
s.Name AS SchemaName,
t
<think>嗯,用户想了解在SQL Server中执ETL操作和存储过程的最佳实践。首先,我需要回忆一下ETL的基本概念,ETL是Extract-Transform-Load的缩写,涉及数据提取、转换和加载。然后结合SQL Server的相关功能,比如Integration Services(SSIS)、存储过程索引优化等。 根据用户提供的引用内容,引用[2]提到SQL Server作为数据仓库的核心,ETL是数据转换的魔法三部曲。这说明ETLSQL Server中的数据仓库构建中很重要。引用[1]提到制定执计划周期性地执ETL过程,并且提到了存储过程的创建和查看。这可能涉及到使用SQL Server代理来调度作业。 另外,引用[4]讨论了列存储索引存储索引ETL过程中的性能比较,指出列存储索引在某些情况下更有效,尤其是在I/O性能较好的情况下。这可能意味着在ETL过程中选择合适的索引类型是关键。 引用[3]提到了无法在事务中执某些存储过程的错误,这可能涉及到存储过程时的注意事项,比如事务管理的问题。因此,在最佳实践中需要注意事务的使用,避免不必要的嵌套事务或者不兼容的操作。 接下来,我需要整理这些信息,分步骤说明如何执ETL操作和使用存储过程的最佳实践。首先,ETL操作通常会使用SSIS,这是SQL Server的集成服务,可以设计数据流任务。然后,存储过程的编写和优化,比如参数化、错误处理、避免长事务等。索引优化方面,需要考虑列存储索引的应用场景,以及ETL过程中批量操作的使用,比如批处理而不是逐处理。此外,执计划的管理,比如使用SQL Server代理定期执ETL任务,监控性能,处理日志和错误。 还需要注意用户可能遇到的常见问题,比如事务中的存储过程错误,这时候需要检查存储过程是否包含不能在事务中执的操作,或者调整事务的隔离级别。另外,数据量大的情况下,如何优化性能,使用分区表或批处理来减少锁竞争和日志开销。 最后,生成相关问题时要覆盖ETL工具选择、存储过程调试、索引选择、事务处理、性能优化等方面,帮助用户进一步探索。</think>### 在 SQL Server 中执 ETL 操作和存储过程的最佳实践 #### **一、ETL 操作执步骤** 1. **使用 SQL Server Integration Services (SSIS)** SSIS 是 SQL ServerETL 核心工具,支持可视化设计数据流任务。例如: - **抽取数据**:从异构数据源(如 Excel、Oracle)提取数据。 - **转换数据**:通过派生列、聚合、条件拆分等组件清洗数据。 - **加载数据**:将结果写入目标表时,建议使用批量插入(`BULK INSERT`)或分区切换(`SWITCH PARTITION`)优化性能[^4]。 ```sql -- 示例:批量插入数据 BULK INSERT TargetTable FROM 'data.csv' WITH (FIELDTERMINATOR = ',', ROWTERMINATOR = '\n'); ``` 2. **优化列存储索引** 对于大规模数据,优先使用**列存储索引**(尤其是聚集列存储索引),可显著压缩数据并提升查询性能。在 ETL 过程中,建议先禁用非聚集索引,加载完成后再重建[^4]。 3. **调度与自动化** 通过 **SQL Server 代理**创建作业,周期性执 ETL 流程。例如: - 调用 SSIS 包。 - 触发存储过程完成增量数据同步。 --- #### **二、存储过程的最佳实践** 1. **参数化与错误处理** - 使用输入/输出参数提高灵活性。 - 通过 `TRY...CATCH` 块捕获异常,记录错误日志。 ```sql CREATE PROCEDURE usp_LoadData @SourcePath NVARCHAR(255) AS BEGIN TRY -- 执ETL逻辑 EXEC sp_executesql N'BULK INSERT TargetTable FROM @Path', N'@Path NVARCHAR(255)', @SourcePath; END TRY BEGIN CATCH INSERT INTO ErrorLog (ErrorMessage) VALUES (ERROR_MESSAGE()); END CATCH ``` 2. **避免事务嵌套冲突** 部分系统存储过程(如 `sys.sp_dropserver`)无法在显式事务中执。需检查存储过程是否包含此类操作,必要时拆分步骤[^3]。 3. **性能优化** - 使用 `SET NOCOUNT ON` 减少网络流量。 - 对高频查询字段添加索引,但避免在 ETL 过程中频繁更新索引(建议加载后重建)。 --- #### **三、关键注意事项** 1. **数据分区策略** 对大型表按时间或范围分区,可加速数据加载和归档。例如: ```sql CREATE PARTITION FUNCTION pf_Yearly (DATETIME) AS RANGE RIGHT FOR VALUES ('2023-01-01', '2024-01-01'); ``` 2. **日志与监控** - 记录 ETL 过程的开始/结束时间和数。 - 使用 SQL Server Profiler 跟踪长时间运的查询。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值