译--列存储索引1:初始列存储索引

2012以后提供了一种不同于传统B树结构的索引类型,就是内存列存储索引。这种索引应用了一种基于列的存储模式,也是一种新的查询执行的批处理模式,并且为特定的负载提供了巨大的性能提升。它是如何构建?如何工作?又是为什么能对性能有如此大的提升,接下来我们用简明的描述和详尽的示例来解释说明。

那么列存储索引究竟是什么?大多数时候,列存储索引被描述作为一种数据仓库和数据报表的功能。事实上,你最有可能就是在这种情况下利用这种索引。然而,即使在OLTP数据库中,你也会遇到一些要从大量数据表中获取数据的报表,它们是非常缓慢的。在合适的计划和谨慎的使用下,甚至这些报表也能利用列存储索引得到性能的提高。一个重要的前提是数据非常大,列存储索引是用来与大数据表一起使用的。虽然没有明确的最小要求,但是作为经验,我建议至少要有一千万的行数据在一个单表中才能受益于列存储索引。

对于这个系列中的例子,将使用 ContosoRetailDW 作为演示 数据库,下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=18279,这是一个626MB的数据库备份,大概1.2GB大小的数据库,对于列存储索引而言有点小,但是对于演示功能来说足够大了。这个数据库本身不包含任何列存储索引,事实上不是一个坏事,为了能更好的体现列存储索引的优点,我们将对同一查询对比带和不带列存储索引的性能。下面的例子是一个典型的来自于BI信息工作人员的查询。

WITH ContosoProducts
AS (SELECT *
    FROM   dbo.DimProduct
    WHERE  BrandName                    = ‘Contoso‘)
SELECT     cp.ProductName,
           dd.CalendarQuarter,
           COUNT(fos.SalesOrderNumber) AS NumOrders,
           SUM(fos.SalesQuantity)      AS QuantitySold
FROM       dbo.FactOnlineSales         AS fos
INNER JOIN dbo.DimDate                 AS dd
      ON   dd.Datekey                   = fos.DateKey
INNER JOIN ContosoProducts             AS cp
      ON   cp.ProductKey                = fos.ProductKey
GROUP BY   cp.ProductName,
           dd.CalendarQuarter
ORDER BY   cp.ProductName,
           dd.CalendarQuarter;

Listing 1: 典型的BI查询

在我的笔记本上,这个查询平均花费了6.27秒来读取已经在缓存中的数据,假如数据被直接从硬盘上读取这个执行将花费8.11秒。由于FactOnlineSales 表中有超过12500000行的数据,这个查询必须扫描整个聚集索引,其实这样还不错,但是假如你整天面对这样的查询,这样的迟缓的响应将变成一个非常恶心的事情,同时也能联想到如果数据库是十倍甚至百倍大小时回事什么样的性能表现?

注意这些执行时间是基于硬件设备的使用,假如重复执行这些测试在一个高端设备上,这些查询可能会非常迅速。当然如果在一个三年前的廉价笔记本上,将更缓慢的执行。不过,即使如此,我们也将看到在创建列存储索引后将会极大的提升执行效率。

创建列存储索引

列存储索引有两个类型:聚集和非聚集。有很多相似之处两者之间,也有很多不同。其中一个不同是在2012中只有非聚集列存储索引。2014中才加入了聚集的版本。我们将创建一个非聚集列存储索引,以便读者能在没SQLServer2014的情况下实现。

CREATE NONCLUSTERED COLUMNSTORE INDEX NCI_FactOnlineSales
ON dbo.FactOnlineSales
   (OnlineSalesKey,
    DateKey,
    StoreKey,
    ProductKey,
    PromotionKey,
    CurrencyKey,
    CustomerKey,
    SalesOrderNumber,
    SalesOrderLineNumber,
    SalesQuantity,
    SalesAmount,
    ReturnQuantity,
    ReturnAmount,
    DiscountQuantity,
    DiscountAmount,
    TotalCost,
    UnitCost,
    UnitPrice,
    ETLLoadID,
    LoadDate,
    UpdateDate);

Listing 2: 创建非聚集存储索引

执行这个创建将花费一些时间(我必须要等待接近43秒),但是这是一个一次性的操作,在真实的数据仓库中会在夜间完成这一典型的操作。一旦索引被创建,它会提高SQLServer 中很多查询的效率。

我们获得了什么?(优点)

当我们再次运行listing 1的代码,结果和以前的一样,但是这个结果几乎是即刻返回的。整个查询只用了0.34秒,是之前没有加入列存储索引速度的18倍多。当然如果从硬盘上读取的话,即使是列存储索引也会变慢,大约需要1.54秒,不过这仍然要比之前的8.11秒快了5倍多。

缺点

这个由非聚集列存储索引获得的性能提升令人印象深刻的,但是也需要在书写查询的时候非常小心。几乎每个带有列存储索引的表查询都能提高效率,但是你必须带着许多限制来书写代码从而获得更大的性能潜力。比如其中一个这样限制是有关于外部连接的。

假如编写 listing 1代码的编程人员打算将BrandName为“Contoso ”的所有产品,即使没有卖出去过的,都包含在结果中,那么就需要将Inner Join 变为Right Outer Join,如下listing3 中所示:

WITH ContosoProducts
AS (SELECT *

FROM   dbo.DimProduct

WHERE  BrandName                    = ‘Contoso‘)

SELECT     cp.ProductName,

dd.CalendarQuarter,

COUNT(fos.SalesOrderNumber) AS NumOrders,

SUM(fos.SalesQuantity)      AS QuantitySold

FROM       dbo.FactOnlineSales         AS fos

INNER JOIN dbo.DimDate                 AS dd

ON   dd.Datekey                   = fos.DateKey

RIGHT JOIN ContosoProducts             AS cp

ON   cp.ProductKey                = fos.ProductKey

GROUP BY   cp.ProductName,

dd.CalendarQuarter

ORDER BY   cp.ProductName,

dd.CalendarQuarter;

Listing 3: 引入一个外链接

在没有列存储索引的情况下(或者带有暗示模仿忽视列存储索引的情况),当数据已经在缓存中时,这个查询运行了6.71秒。包含了变化造成的在执行计划中的额外消耗,这部分大概花费了0.44秒在,耗时增加了接近百分之7。

当在我的SQLServer2012中不带提示的去运行这个查询时,优化器将立即选择一个带有列存储索引的执行计划,结果正如期望是更快的,接近4.24秒。当然这依然是要比6.71秒那种不含列存储索引的效率高的,但是与之前0.34秒的情况比较起来没有明显变化,那到底是为什么在同时都应用了列存储索引的情况下,仅仅从inner改为了outer 就产生了如此大的性能变化呢?

批处理模式

列存储索引是由于使用了一种叫做“批处理执行模式”的模式,用一种完全不同的方式来执行查询,但是在2012中这一模式是有很多限制的,仅有少量操作符可以用来使用这一模式,只要使用了不再这些操作符中的操作符,这个查询将返回到原来的查询模式中。比如Outer Join就是这样的操作符,将会引起查询返回到行模式中,虽然也能获取一部分性能提升,但是不能从批处理模式中得到显著提升。

最快速的方式去核实这个模式就是通过执行计划来查看该查询在SSMS 中的图像。检查两个属性“Estimated Execution Mode” 和“Actual Execution Mode”,下图极为在批处理模式下查询执行计划的示例,两个属性都为batch。

Figure 1-1: 执行计划显示为Batch

当然在2014中批处理模式的操作符增加很多,其中outer join 也是其中之一,总之在性能和限制上,2014都有显著的提高,这一点是毋庸置疑的。

对比效果.

没有一种简单的方式去预测当你创建列存储索引后性能的提升。目前只有通过在真实环境下比较查询性能或者在一个尽可能真实的测试环境下来测试比较,它带来的好处。

对于能够运行在批处理模式下的查询而言,我们已经能看到在添加列存储索引后性能提升了5到70倍,相比较于行模式的查询,性能的提升永远是更小的,一般为50%到20倍的提升。

总结

通过使用列存储索引通过两个因素来提升性能。一个是通过新的索引架构来节省I/O,另一个是批处理模式。很不幸的是,在SQLServer2012中仅有少量操作符可以使用列存储索引,造成许多查询被迫采用行模式执行,丧失了批处理模式的性能获得。不过好消息是,绝大多数的限制在SQLServer 2014 中得到了完善。

时间: 2024-10-23 15:20:22

译--列存储索引1:初始列存储索引的相关文章

Redis 四:存储类型之散列类型

1.散列类型表达方式简介: =========================================== 键 字段 值 =========================================== 前轮 --->富士康 后轮 --->苹果 宝马: 挡风玻璃 --->加多宝 座椅 --->王老吉 方向盘 --->恒大冰泉 =========================================== 散列类型更好的作用于同一个对象,不同属性,对应不同

认识SQLServer索引以及单列索引和多列索引的不同

一.索引的概念 索引的用途:我们对数据查询及处理速度已成为衡量应用系统成败的标准,而采用索引来加快数据处理速度通常是最普遍采用的优化方法. 索引是什么:数据库中的索引类似于一本书的目录,在一本书中使用目录可以快速找到你想要的信息,而不需要读完全书.在数据库中,数据库程序使用索引可以重啊到表中的数据,而不必扫描整个表.书中的目录是一个字词以及各字词所在的页码列表,数据库中的索引是表中的值以及各值存储位置的列表. 索引的利弊:查询执行的大部分开销是I/O,使用索引提高性能的一个主要目标是避免全表扫描

MySQL索引与事务、存储引擎MyISAM和InnoDB (理论+实践篇)

索引的概念 数据库中的索引与书籍中的目录类似 在一本书中,无须阅读整本书,利用目录就可以快速查找所需信息 书中的目录是一个词语列表,其中注明了包含各个词的页码 数据库索引 在数据库中,索引使数据库程序无须对整个表进行扫描,就可以在其中找到所需数据 数据库中的索引|是某个表中一-列或者若干列值的集合,以及物理标识这些值的数据页的逻辑指针清单 索引的的作用 设置了合适的索引之后,数据库利用各种快速的定位技术,能够大大加快查询速率 特别是当表很大时,或者查询涉及到多个表时,使用索引可使查询加快成3 F

普通索引、唯一索引、主索引、外键索引、复合索引、非主码索引、聚集主码(聚集索引)、单列索引、多列索引

强烈建议看了第一个参考文献再来看这个篇博文,因为此处不准备讲底层数据结构的实现. 索引:索引(Index)是帮助MySQL高效获取数据的数据结构.提取句子主干,就可以得到索引的本质:索引是数据结构.其表达的是存储引擎的范畴,也就是说只有在存储引擎级别谈索引才有意义.MyISAM.InnoDB.Memory等.此处单纯就InnoDB存储引擎讨论. B-TREE.B+TREE数据结构. 在数据之外,数据库系统还维护着满足特定查找算 法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就可以在这

原创 MySQL的索引与事务、存储引擎

索引的概念 数据库中的索引与书籍中的目录类似 在一本书中,无须阅读整本书,利用目录就可以快速查找所需信息书中的目录是一个词语列表,其中注明了包含各个词的页码 数据库索引 在数据库中,索引数据库程序无须对整个表进行扫描,就可以在其中找到所需数据数据库中的索引是某个表中一列或者若干列值的集合,以及物理标识这些值的数据页的逻辑指针清单 索引的作用 设置了合适的索引之后,数据库利用各种快速的定位技术,能够大大加快查询速率:特别是当表很大时,或者查询涉及到多个表时,使用索引可使查询加快成千倍:可以降低数据

数据库:存储引擎+InnoDB+TokuDB+ MyIASM +Memory+索引+三范式等

存储引擎概念数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据.不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能.现在许多不同的数据库管理系统都支持多种不同的数据引擎. 存储引擎主要有: 1. MyIsam , 2. InnoDB, 3. Memory, 4. Archive, 5. Federated . InnoDB(B+树) InnoDB 底层存储结构为B+树, B树的每个节点对应i

SQL联合索引 与 单一列的索引

SQL联合索引 与 单一列的索引 标签: sqlwebobjectstatistics优化磁盘 2012-06-12 13:46 27992人阅读 评论(1) 收藏 举报  分类: 数据库(94)  转自:http://liqita.iteye.com/blog/1205544 背景:目前WEB的普及太快,很多网站都会因为大流量的数据而发生服务器习惯性死机,一个查询语句只能适用于一定的网络环境.没有优化的查询当遇上大数据量时就不适用了. 联合索引使用结论: 1):查询条件中出现联合索引第一列,或

Atitit.  单列索引与多列索引 多个条件的查询原理与设计实现

Atitit.  单列索引与多列索引 多个条件的查询原理与设计实现 1. MySQL只能使用一个索引1 1.1. 最左前缀1 1.2. 从另一方面理解,它相当于我们创建了(firstname,lastname,age).(firstname,lastname)以及(firstname)这些列组合上的索引.2 2. 一条 sql 可以使用多个索引2 2.1. 什么是索引合并2 2.2. 使用索引合并有啥收益3 2.3. 具体的索引合并流程 4 3. Referred.4 1. MySQL只能使用一

关于复合索引中的2个索引列谁在前谁在后的进一步讨论--实践篇

关于复合索引中的2个索引列谁在前谁在后的进一步讨论--实践篇: 上一次在长老的QQ群里边说了这么一个例子: create table test_pk( id varchar2(10), create_dt date); alter table test_pk modify (id varchar2 (30 )); insert into test_pk select object_id, sysdate from dba_objects; commit 需要执行的查询是: select * fr

正确理解Mysql的列索引和多列索引

MySQL数据库提供两种类型的索引,如果没正确设置,索引的利用效率会大打折扣却完全不知问题出在这. [c-sharp] view plain copy CREATE TABLE test ( id         INT NOT NULL, last_name  CHAR(30) NOT NULL, first_name CHAR(30) NOT NULL, PRIMARY KEY (id), INDEX name (last_name,first_name) ); 以上创建的其实是一个多列索引