简介

首先介紹列存储的概念: 传统的数据库存储是行存储。对于SQL Server来说,每个page是8K;往page里面塞数据,假设该表每条数据长度是500字节,那么这个page 先塞第一条数据,然后再塞第二条数据,大概能塞 8K/500=16条数据。注意这里每一条数据都是包括所有字段(column)的。如图所示,下面是若干个page,每个page塞满了一行一行的数据。行存储示意图。

接下来介绍列存储,是一个column一个column塞,而且在SQL Server里,是向row group或者segment塞。列存储示意图

如图,该表有5个字段(column),每个红色柱体是一个Segment;每5个segment组成一个row group。Segment只包含一个column的数据,而row group包含所有column的数据。

每个Segment最多包含1百万条该column的数据;从性能上说,1百万条能达到性能最优(数量越大,压缩比越大),数量越少,该segment的性能越差。

列存储对比行存储有什么好处: 行存储适合OLTP系统,就是多用户使用,很多update/insert/delete,SQL 语句处理的对象都是几条数据或者几百条数据(数据量不大);

列存储适合数据仓库,用户数很少,数据量巨大,数据变化少(除了ETL)。在SQL Server中,ColumnStore index能把大量的数据压缩到1/10,从而减少IO,CPU和memory的使用,从而带来性能的飞跃;ColumnStore 除了压缩,还使用了Batch mode,segment eliminate等技术,对性能有很大提升。

2. ColumnStore Index 适用的场景

和其他技术一样,不能适合所有场景;如果选用的场景不适合,反而会带来性能的急剧下降。

(1) 用星性/雪花模型建模的数据仓库

(2) 该表(或者分区)的记录数要大于1百万

(3) 大部分SQL 语句是报表类的语句,就是range scan 而不是 seek。

(4) 该表的数据很少进行update/delete,大量的insert是可以的。

(5) 该表不能有varchar(max), nvarchar(max), or varbinary(max) 数据类型

(6) 对于OLTP数据库,在某些特定的场景下也可以使用columnstore index :real-time operational analytics

3. Column Store的物理结构

ColumnStore Index 除了Row group 还包括 DeltaStore。假设该表有1105万条记录,每个rowgroup容纳100万条,那么总共有11个row group,还有5万记录放在Deltastore里面。

DeltaStore是用来存放不够数量(这里是100万)的数据,行存储,没有压缩;而rowgroup都是列存储,而且压缩了。

随着insert 数据增多,Deltastore的数量增加,如果数量增加到100万,该Deltastore 会停止接收数据,变成row group,也就是 列存储,压缩;如果还有数据insert,会生成新的Deltastore。

Columnstore Index 的组成部分除了 Row Group,Delta store,还有 Delted Bitmap.

Columnstore index 删除记录并不是物理删除,而是逻辑删除,在 Delted Bitmap加一个标记; Delted Bitmap会记录整个表被删除的记录;SQL Server对该表做query的时候,除了查询row group,Delta store(row store)还要查询 Delted Bitmap,把三者的结果Union才是最后的结果。

那么ColumnStore Index什么时候做物理删除? 对index 进行rebuild或者reorganize的时候。

对Columnstore index进行update,并不是物理update,而是delete该条记录然后insert一条新的记录。

ColumnStore Index 结构小结:

(1) 包括Row Group(compressed,列存储),Delta Store (也叫Delta Row group,行存储),Deleted Bitmap (存储被删除的记录的信息)。

(2) 从SQL Server2016开始,一个表创建了ColumnStore index后,还可以创建传统的行存储的索引----non clustered index(NCI)。

(3)ColumnStore index本身不排序的,所以查询某一条记录都需要 全表扫描(full table scan);不排序这个特性对于insert是利好,performance很好;对于delete/update不好,特别表比较大的时候。 因为delete/update某一条记录,需要先找到它,而查找的代价对于ColumnStore Index 比较大。

(4) 对于上面第三点,要快速的找到某一条或几条数据,可以在ColumnStore index基础上再创建传统的行存储的索引----non clustered index(NCI)。

(5) 在ColumnStore index基础上再创建传统的行存储的索引----non clustered index(NCI),好处不仅是performance,还能给这个表加上 唯一性约束、主键约束和外键约束等约束。当然,这些都只能在SQL2016或之后的版本才能实现。

4. 如何发现某些表适合创建ColumnStore index。

首先它比较适合于数据仓库,但数据仓库的每个表都能创建ColumnStore Index吗?另外OLTP环境可以使用CCI吗?

另外可以用 DMV sys.dm_db_index_operational_stats来查看某个表的过往操作:

(1) 如果50%以上的操作是range scan,而不是seek

(2) update/delete的操作少于10%

那么这个表很适合创建cluster columnstore index(CCI);当然还有一个前提,该表足够大,至少1百万条记录,越大越好。

如何估计某个表创建clustered columnstore index 之后的压缩率? 在SQL 2019中,可以使用sp_estimate_data_compression_savings 来预估压缩率。

该sp在数据库中执行以下操作:

•创建临时表 T

•把该表的数据进行采样,载入一部分数据到T

•查看T的大小

•对T 进行列存储压缩,查看压缩后的大小

5. 快速的装载数据到已经创建 CCI的表中

(1) 装载外部文件

bulk insert tableA FROM 'c:\temp\fileA.csv'

csv文件的数据并行的装载到多个Row Group和多个Delta Store 中;超过102400条记录的数据进入Row Group,列压缩;没有超过102400条记录的数据进入 Delta Store (Delta Row group)。

因为Row Group提供了高的压缩比,所以装载数据产生的日志也会少很多;

SQL Server会自动的使用并行操作,同时向多个Row Group装载数据。

(2) 从其他表装载数据

Insert into select * from

与“装载外部文件”很类似,超过100k条记录的数据进入Row Group,列压缩;没有超过100k条记录的数据进入 Delta Store (Delta Row group)。

不过SQL Server不会自动的使用并行操作,要使用tablock才能触发并行。

insert into ccitest with (TABLOCK) select * from dbo.FactResellerSalesXL (能并行)

(3) 使用SSIS 来装载数据

从SQL2016开始,有一个新的参数 AutoAdjustBufferSize,它能根据batchsize来自动调整 buffer size,对性能有极大提升。

6. CCI 的性能

CCI 除了压缩比大带来的CPU/memory/IO的减少,还使用了 Batch mode,segment eliminate和 并行来提升性能。

(1) Batch Mode

Batch mode 从字面上,就是批处理,就是一次处理几百条数据,而不是一条一条处理数据;

比较适合于大数据量的数据仓库。

Batch mode 是从SQL Server 2012开始和ColumnStore Index 一起使用的;在SQL 2019之前,Batch mode只能在列存储中使用,从SQL 2019开始,batch mode也能在row store使用。

对于 SQL 语句: selectProductKey,OrderQuantityfromFactResellerSalesXL_CCI where OrderQuantity<3

batch mode会在内存中 占用64K大小的内存,形成上图中的vector,先scan 该表把64k的数据放到vector中,然后用predictte来过滤(OrderQuantity<3)。符合过滤条件的,会在memory当中的bitmap打上标记;bitmap在上图的最左边。

每次处理64k大小的数据。

在SQL 2016之前,很多函数不支持 batch mode,包括sum,avg,min,rank等;还有distinct,left join,group by, order by等也不被支持。 总之一句话,要用Columnstore index ,要用batch mode,不要选SQL 2012/2014,要选SQL 2016/2017/2019

(2) Segment elimination and column elimination

Segment elimination 也叫 Rowgroup elimination

从上图可知,如果表SalesTable创建了ColumnStore Index,SQL Server会自动把不需要的字段(column),不需要的rowgroup过滤掉。

CCI如何过滤Row group/segment?请看下面的元数据:

SELECT segment_id, object_name(p.object_id), s.column_id, s.min_data_id, s.max_data_id FROM sys.column_store_segments s, sys.partitions p

where p.object_id = object_id('FactResellerSalesXL_CCI') and

p.hobt_id = s.hobt_id and column_id = 2

从上图可以看到,该表的CCI的第二个字段(column)有12个segment,每个segment都记录了最大值,和最小值,这样sql语句查询的时候,很容易过滤不需要的segment。

另外执行 下面的语句:

set statistics IO ON

set statistics TIME ON

SELECT Productkey, OrderQuantity as curqty,

Sum (OrderQuantity) OVER (ORDER BY ProductKey) AS TotalQuantity

FROM FactResellerSalesXL_CCI WHERE orderdatekey in ( 20060301,20060401)

正因为第二个字段(orderdatekey)的元数据存储了最大值/最小值,所以上面的SQL 直接skip了 7个segment,只在另外的5个segment中查找数据

(3) Aggregate Pushdown

从SQL2016 开始,对于Select SUM(sales) from 这样的语句,当表非常大的时候,Aggregate Pushdown 特性可以极大提高性能。

简单的来说,对于sum/avg/group by/max/count这样·的函数,表有数以亿计的记录,SQL Server 会自动的把处理大量数据的工作放在执行计划的第一步,也就是最接近存储的地方,这样传送给执行计划的下一步的数据会大大减少。

该特性自动进行,不用任何调整。

7. CCI 的维护。

和其他传统的row store index一样,CCI也会有碎片(fragment)。

有两类碎片:

1.对于CCI,只有一个Delta Store是正常的,如果有多个Delta Store(超过10个以上)那就是碎片化,需要进行维护

2. 对于列存储的Row Group,删除数据只是逻辑删除,没有物理删除;如果删除的数据占该RowGroup中超过10%,那就是碎片化,需要进行维护。

从SQL 2016开始,使用 Alter Index on

(1) self merge

当Row group中的逻辑删除记录数占到10%以上,就会使用self merge物理删除这些记录;

(2)merge

两个Row group的记录数加起来都不到1百万,那么merge操作会把这两个RG 合并成一个

8. Columnstore 和 In-Memory OLTP的结合

首先解释什么是 Real-time Operational Analytics。

之前介绍的传统的数据仓库,适合使用 CCI;对比传统的数据仓库,现在有一些混合型的应用场景,就是既有OLTP,也有数据仓库的查询。这种场景,就是直接在OLTP的数据库上跑一些报表的大SQL,好处如下:因为没有专门的数据仓库,节约了硬件;

没有经过ETL,OLTP的数据一般是最新的,而传统的数据仓库往往经过ETL,数据往往不是最新的。

因为没有ETL,Stage 数据库的硬件,ETL的维护、软件的成本都节省了。

缺点也很明显:不能像传统数据仓库,有多个数据源

没有经过ETL,数据的结构不能像传统数据库那样实现星形/雪花建模

同时在一个数据库上跑OLTP和报表SQL,互相影响性能

前面介绍了,Real-time Operational Analytics可以使用disk based table(磁盘表),也可以使用in memory table;如果使用前者,就可以使用noclustered columnstore index;如果使用in memory table,必须使用 clustered columnstore index。下面介绍后者

首先该表是 in-memory OLTP table,表上可以创建hash index 或range index,这些都是传统的row store(行存储),只是把这些都搬到内存当中;图中最下面是columnstore index(列存储),也是放着memory当中。

上图告诉我们,数据实现了冗余,in memory table存储了数据,而内存中的columnstore index也存储了数据,而且是数据、索引放在一起。每当有数据insert,先对in memory table的hot 部分(尾部)进行insert,当这一部分的记录数达到1百万,这些数据会转移到columnstore index 当中。

当SQL 语句是OLTP类型,in memory table 可以很好的处理,效率非常高,具体原理要参考in memory OLTP特性。

当SQL 语句是报表类语句,columnstore index可以高效处理。

从上图看,该场景需要比较多的memory。

predicate 列存储索引扫描_ColumnStore index (列存储索引)解析相关推荐

  1. 位图索引(Bitmap Index)——位图索引与数据DML锁定

    位图索引相对于传统的B*树索引,在叶子节点上采用了完全不同的结构组织方式.传统B*树索引将每一行记录保存为一个叶子节点,上面记录对应的索引列取值和行rowid信息.而位图索引将每个可能的索引取值组织为 ...

  2. Oracle 表的访问方式(2)-----索引扫描

    索引扫描(Index scan) 我们先通过index查找到数据对应的rowid值(对于非唯一索引可能返回多个rowid值),然后根据rowid直接从表中得到具体的数据,这种查找方式称为索引扫描或索引 ...

  3. Oracle 索引扫描的五种类型

    之前在讨论CBO和RBO的时候提到了索引扫描的几种类型. Oracle Optimizer CBO RBO http://blog.csdn.net/tianlesoftware/archive/20 ...

  4. MySQL-索引优化篇(2)_使用索引扫描来优化排序

    文章目录 生猛干货 官方文档 使用索引扫描来优化排序 索引的列顺序和Order By子句的顺序完全一致 索引中所有列的方向(升序.降序)和 order by子句完全相同 order by中的字段全部在 ...

  5. Oracle索引扫描方式

    文章目录 0.参考资料 1.索引扫描方式和索引类型概述 2.索引唯一扫描(index unique scan) 3.索引范围扫描(index range scan) 4.索引跳跃扫描(index sk ...

  6. Oracle索引梳理系列(八)- 索引扫描类型及分析(高效索引必备知识)

    理解oracle索引扫描类型的特点以及具体触发的条件,对于通过合理地使用索引,进行sql优化至关重要(例如组合索引的引导列的选择问题). 在总结索引扫描类型前,需要再次强调关于索引特点的几个关键点: ...

  7. SQL SERVER中什么情况会导致索引查找变成索引扫描

    原文:SQL SERVER中什么情况会导致索引查找变成索引扫描 SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方 ...

  8. oracle9可以访问8,使用Oracle9i全索引扫描快速访问数据

    为了实现Oracle关于增加SQL优化查询智能的承诺,Oracle9i增强了全索引SQL执行计划以支持基于功能的索引(function-based index).在Oracle8中,SQL优化器添加了 ...

  9. 面向初学者的 SQL Server 查询执行计划(1)——聚集索引运算符(Clustered Index)

    在本文中,我们将讨论与聚集索引相关的各种执行计划运算符,以及它们的作用.它们何时出现以及它们何时出现. 执行计划中的每一个运算符都会提供一些有关 SQL Server 运行方式的指标. 我们需要理解这 ...

最新文章

  1. Nat. Mach. Intell.| 机器学习显著降低药物组合筛选成本
  2. 逐飞关于第15届智能车竞赛相关工作
  3. LR接口测试---基于http协议之get/post
  4. js之字面量、对象字面量的访问、关键字in的用法
  5. ML之FE:基于BigMartSales数据集利用Featuretools工具实现自动特征工程之详细攻略daiding
  6. Win11系统如何设置任务栏新消息提醒
  7. Java面试之synchronized和Lock有什么区别?
  8. 自动驾驶——多目标跟踪模块的学习笔记
  9. 想象力惊人!只凭一句话,AI就能脑补出动漫小片
  10. 明明选的是个人用途,为什么会被检测商用?
  11. 【Tips小技巧】电脑全屏截图网页滚动截图
  12. 《IPD:华为研发之道》读书介绍
  13. 【Python 爬虫教程】代理ip网站有哪些?
  14. 网络协议实验四 ARP 协议分析实验
  15. 解决Android 8.0和9.0无法获取SSID (unknow ssid)
  16. Blackbox_exporter概述
  17. 泛型类、泛型方法的使用与理解
  18. IVY throws IOException Resetting to invalid mark原因及解决办法
  19. 三星s6如何打开位置服务器,三星手机如何定位对方手机所在位置(如何知道对方手机位置)...
  20. 【TEMP】临时表空间的工作原理及维护方法

热门文章

  1. mongodb+java_Java EE + MongoDb与Apache TomEE和Jongo Starter项目
  2. JEP 342:JVM和幽灵
  3. Spring Data Pivotal Gemfire教程
  4. Spring管理的Hibernate事件监听器
  5. gradle 插件 自定义_Gradle自定义插件
  6. jax-rs jax-ws_JAX-WS入门
  7. javafx_JavaFX 2 GameTutorial第2部分
  8. 具有Couchbase,Java EE和WildFly的CRUD Java应用程序
  9. datanucleus_DataNucleus 3.0与Hibernate 3.5
  10. Java性能调优:充分利用垃圾收集器