SQL Server 2012 列存储索引分析(翻译)
一、概述
列存储索引是SQL Server 2012中为提高数据查询的性能而引入的一个新特性,顾名思义,数据以列的方式存储在页中,不同于聚集索引、非聚集索引及堆表等以行为单位的方式存储。因为它并不要求存储的列必须唯一,因此它可以通过压缩将重复的列合并,从而减少查询时的磁盘IO,提高效率。
为了分析列存储索引,我们先看看B树或堆中的数据的存储方式,如下图,在page1上,数据是按照行的方式存储数据的,假设一行有10列,那么在该页上,实际的存储也会以每行10列的方式存储,如下图中的C1到C10。
假设我们执行select c1,c2 from table时,数据库会读取整个page1,显然,从C3到C10并不是我们想要的数据,但因为数据库每次读的最小单位是一页,因此这些不得不都加载到内存中。如果数据页多时,必然要消耗更过的IO和内存。
如果是列存储索引,数据按列的方式存储在一个页面中,如下图,page1中只存储表中C1列,page2只存储c2列,以此类推,page10存储c10列。
假设我们执行select c1,c2 from table时,结果会怎样呢?数据库只会读page1和page2,至于page3到page10因为没有对应的数据,数据库不会去读这些页,也不会加载到内存中,相比行存储而言,减少了磁盘IO和优化了内存的使用。
下文做了一个技术验证,用来分析列存储索引的查询性能。
思路:做两张一模一样的分区表(分区表可以更好的展示效果),含1000000行数据,然后给其中一张表(sales2)建立聚集索引,另一张表(sales)建列存储索引,最后来对比这两张表的查询性能。
二、创建表
先做两张相同的表,创建的语句如下:
create partition function pf (date) as range left for values
('20110712', '20110713', '20110714', '20110715', '20110716');
go
create partition scheme ps as partition pf all to ([PRIMARY]);
go
create table sales (
[id] int not null identity (1,1),
[date] date not null,
itemid smallint not null,
price money not null,
quantity numeric(18,4) not null)
on ps([date]);
go
declare @i int = 0;
begin transaction;
while @i < 1000000
begin
declare @date date = dateadd(day, @i /250000.00, '20110712');
insert into sales2 ([date], itemid, price, quantity)
values (@date, rand()*10000, rand()*100 + 100, rand()* 10.000+1);
set @i += 1;
if @i % 10000 = 0
begin
raiserror (N'Inserted %d', 0, 1, @i);
commit;
begin tran;
end
end
commit;
GO
三、查询含聚集键的表
(1) 创建表sales2的聚集键
CREATE CLUSTERED INDEX Clu_sales2_index ON sales2(date,price,quantity) on ps([date]);
查看表的存储信息
select * from sys.system_internals_partitions p
where p.object_id = object_id('sales2');
select au.* from sys.system_internals_allocation_units au
join sys.system_internals_partitions p
on p.partition_id = au.container_id
where p.object_id = object_id('sales2');
GO
该表一共有6个分区,其中只有4个分区有数据,每个分区250000行,已使用1089页,。
(2) 执行查询语句 (注意清掉缓存)
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
SELECT COUNT(*),SUM(price*quantity) FROM sales2 WHERE date='20110713';
GO
我们可以看到,在这个查询中,一共有1089次逻辑读(等于该表每个分区中的已使用页数),CPU时间为62毫秒,占用时间为261毫秒。
备注:CPU时间,执行语句的时间;
占用时间,从磁盘读取数据开始到完全处理使用的时间。
四、查询含列存储索引的表
(1) 创建表sales的列存储索引
create columnstore index cs_sales_price on sales ([date], price, quantity) on ps([date]);
查看表的存储信息:
select * from sys.system_internals_partitions p
where p.object_id = object_id('sales')
and index_id = 2;
select au.* from sys.system_internals_allocation_units au
join sys.system_internals_partitions p
on p.partition_id = au.container_id
where p.object_id = object_id('sales')
and index_id = 2;
GO
在建有列存储索引后,表的行数并没有改变,每个分区依然还是250000行,但页面数明显减少,且页的类型由原来的IN_ROW_DATA变成了LOB_DATA。
(2) 执行查询语句
select count(*), sum(price*quantity) from sales where date = '20110713'
在这个查询中,一共有363次逻辑读(等于该表每个分区),CPU时间为93毫秒,占用时间为191毫秒。
总结
从两次查询的结果来看,无论是逻辑读的次数和占用时间,在列存储索引的表中执行查询明显要快于聚集索引的表。
而且,从两种表的存储结构中可以看到,列存储索引占用的页面数量较聚集索引的少,这也印证了列存储索引的压缩功能。
备注:通过两次查询,我们看到两者的CPU时间差距不是很大,相反聚集索引占用的时间更小,考虑到列存储实际上是压缩存储,我认为在一张小表或者简单的表中,对列存储索引差查询或许会占用多的CPU时间,因为查询时需要解压(我没有具体验证过),因此列存储索引在小表中的优势主要体现在IO和空间上,实际上列存储索引的对象往往是含有大数据量的表,数据量越大,其优势体现越明显。
说明:准确的说本文并不是原创,文章是从如下地址翻译过来,然后结合自己的实践,增加了一些自己的理解。
http://rusanu.com/2011/07/13/how-to-update-a-table-with-a-columnstore-index/
SQL Server 2012 列存储索引分析(翻译)的更多相关文章
- SQL Server 2012 列存储索引分析(转载)
一.概述 列存储索引是SQL Server 2012中为提高数据查询的性能而引入的一个新特性,顾名思义,数据以列的方式存储在页中,不同于聚集索引.非聚集索引及堆表等以行为单位的方式存储.因为它并不要求 ...
- 微软BI 之SSAS 系列 - 在 SQL Server 2012 下查看 SSAS 分析服务的模型以及几个模型的简单介绍
在SSDT中部署一个 SSAS 项目到本地服务器上出现错误. You cannot deploy the model because the localhost deployment server i ...
- SQL Server 2012 批量重建索引
关于索引的概念可以看看宋大牛的博客 T-SQL查询高级—SQL Server索引中的碎片和填充因子 整个数据库的索引很多,索引碎片多了,不可能一个个的去重建,都是重复性的工作,所以索性写了个存储过程, ...
- 在SQL Server 2014里可更新的列存储索引 (Updateable Column Store Indexes)
传统的关系数据库服务引擎往往并不是对超大量数据进行分析计算的最佳平台,为此,SQL Server中开发了分析服务引擎去对大笔数据进行分析计算.当然,对于数据的存放平台SQL Server数据库引擎而言 ...
- SQL Server 2014聚集列存储索引
转发请注明引用和原文博客(http://www.cnblogs.com/wenBlog) 简介 之前已经写过两篇介绍列存储索引的文章,但是只有非聚集列存储索引,今天再来简单介绍一下聚集的列存储索引,也 ...
- SQL Server 列存储索引强化
SQL Server 列存储索引强化 SQL Server 列存储索引强化 1. 概述 2.背景 2.1 索引存储 2.2 缓存和I/O 2.3 Batch处理方式 3 聚集索引 3.1 提高索引创建 ...
- 解读SQL Server 2014可更新列存储索引——存储机制
概述 SQL Server 2014被号称是微软数据库的一个革命性版本,其性能的提升的幅度是有史以来之最. 可更新的列存储索引作为SQL Server 2014的一个关键功能之一,在提升数据库的查询性 ...
- SQL Server ->> ColumnStore Index(列存储索引)
Columnstored index是SQL Server 2012后加入的重大特性,数据不再以heap或者B Tree的形式存储(row level)存储在每一个数据库文件的页里面,而是以列为单位存 ...
- SQL Server 列存储索引概述
第一次接触ColumnStore是在2017年,数据库环境是SQL Server 2012,Microsoft开始在SQL Server 2012中推广列存储索引,到现在的SQL Server 201 ...
随机推荐
- PHP 用html方式输出Excel文件时的数据格式设置
1) 文本:vnd.ms-excel.numberformat:@ 2) 日期:vnd.ms-excel.numberformat:yyyy/mm/dd 3) 数字:vnd.ms-excel.numb ...
- AX2009按照批次生产日期预留
AX2009如果想按照批处理号预留,它默认是按照InventBatchId排序的,但并不是InventBatchd小的批次的生产日期就早,所以这个逻辑得改一下,让它按照InventBatch的Prod ...
- Xshell
http://baike.baidu.com/link?url=5lc5IxVVauitYSbqlOXJBvrvM3qVfMhzz6x_xu2cOMb108Ln9Wk7iJ3f46vG0kBninKw ...
- python-操作MySQL数据库
1.安装MySQLdb? 为了用DB-API编写MySQL脚本,必须确保已经安装了MySQL.复制以下代码,并执行: #!/usr/bin/python # -*- coding: UTF-8 -*- ...
- Tomcat启动过程中找不到JAVA_HOME解决方法
在XP上明明已经安装了JDK1.5并设置好了JAVA_HOME,可偏偏Tomcat在启动过程中找不到. 报错信息如下:Neither the JAVA_HOME nor the JRE_HOME en ...
- CentOS 7将网卡名称eno16777736改为eth0
http://www.linuxidc.com/Linux/2015-09/123396.htm Linux系统版本:CentOS_7(64位) 一.前言: 今天将CentOS 6.5装回了CentO ...
- C#将Enum枚举映射到文本字符串
介绍 当将以前的C代码移植到C#中时,我快发疯了,因为有很多的数组需要将常量映射到字符串.当我在寻找一个C#的方法来完成的时候,我发现了一个自定义属性和映射的方法. 如何使用代码? 对每一个enum枚 ...
- 本地缺Android SDK版本20,Unable to resolve target 'android-20'
解决方案一 本地缺Android SDK版本20,Unable to resolve target 'android-20' 通过SDK Manager安装一个Android 20. 解决方案二: L ...
- iOS开发之AFNetworking 3.0.4使用-OC
GET请求 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; [manager GET:URL parameters: ...
- SMTP的相关命令
SMTP是Simple Mail Transfer Protocol的简写. 邮件是日常工作.生活中不能缺少的一个工具,下面是邮件收发的流程. Image 邮件的发送,主要是通过SMTP协议来实现的. ...