• 如何写出高效能TSQL - 关于索引不可不知道的事

    原文地址:http://blogs.technet.com/b/technet_taiwan/archive/2015/01/23/tsql-series-0123.aspx

    本文将分成五大单元,分别带您了解:

    索引简介

    索引基本知识

    索引类型介绍

    索引设计注意事项

    进阶推荐

     


    简介

    TSQL是查询SQL Server的核心,而索引则是提高查询效能的主角,如要写出高效能TSQL则无可避免需搭配正确索引,因为SQL Server需透过正确索引才可以快速有效地找到与索引键值相关数据,有了正确索引SQL Server就不需要扫描数据页(data page)上每一笔数据,而在众多查询效能调校技术中,透过建立并设计正确索引算是最基本的手法 (通常来说也是最有效、最快能看到效果的),所以了解索引观念和特性,可以帮助我们在开发阶段设计规划正确索引,而且我们认为不管是开发人员或DBA都应该了解索引该如何设计,因为都有可能接收用户最直接的感受,说白话一点,每一句查询TSQL都要以最短时间响应给用户。但由于索引主题范围庞大,所以一开始我们会介绍索引基本知识、B-tree 结构等,后面介绍索引类型、案例分享及设计须注意的方向,主要是希望透过本文可以让大家快速建立正确索引。

     

    索引基本知识

    SQL Server 如何使用索引

    我们都知道索引可以提高查询效能,但相对也增加新增(Insert)、删除(Delete)和更新(Update)数据处理成本,所以对整体效能来说找一个合适平衡点相当重要。

    当一个数据表没有索引时,数据存放的顺序绝不是依照数据新增顺序,这是因为SQL Server Database Engine会自我处理数据储存位置,所以基本上,我们无法事先预测数据储存在数据页上是否都连续且都在同一区段中,而当一句Select送给SQL Server时,因为没有索引,这时SQL Server必须扫描整个数据表,以及该数据表的所有数据页和数据页上的每一笔数据,最后才返回用户最终所需要的数据结果集,这样的操作就称为表扫描(Full Table Scan)

    当数据表上有索引时 (假设索引设计正确),这时数据表上的数据一定会经过排序,所以SQL Server将基于该索引键值和结构来定位 (透过指针) 数据位置,简单来说只搜寻必要的数据页,而这些数据页已经包含用户最终所需要的数据结果集,这样的操作就称为索引搜寻(Index Seek)

    B-tree 索引结构

    SQL Server所有索引基本上都采用B-tree结构,除了xml索引、全文检索索引(full-text)、数据行存放区索引(columnstore index)和内存优化索引(Memory-optimized indexes)不用B-tree xml 索引是存放在 SQL Server 底层数据表,全文检索索引是利用自己引擎来处理查德询和管理全文检索目录 (full-text catalogs),数据行存放区索引则是使用 in-memory 技术,内存优化索引则是使用 BW-tree 结构。

    一个标准的B-tree结构 (图1)是由根结点(root)开始的页面,下面有一或多个中继层节点及一或多个分叶(Leaf)节点构成。

    1 B-tree结构。

     

    一个B-tree 构一定是平衡的,这代表每一层左右页面数量一定相等,最末的分叶页面包含了排序后的索引数据,每页索引数据列数量视索引所含数据行的储存空间而定。

    根节点及中继层节点包含其下层节点的第一项数据,即表示指向下层数据储存位置的指针 (图2)SQL Server执行查询时会先扫描每一个根节点所在页面,搜寻是否含有查询的值,找到后再以指针指向下一层继续搜寻,如此不断反复处理,直到在最末层的分叶节点中找到数据为止。

    2 索引页面中的根、中继层和分叶节点。

    假设今天我们要在图2中搜寻ProductID199,查询会从根节点开始搜寻,因为ProductID199介于147~789之间,所以SQL Server会从ProductID147开始搜寻并计算Product199可能位置,指向下层 (中继层) ProductID147开始搜寻至ProductID306节点后,再指向下层 (分叶层) 搜寻ProductID199所在位置(147~208),由于此时已在最末层,故可以在该层找到数据,且SQL Server也不需要去搜寻其他节点或页面找ProductID199如果 ProductID199 不在数据表中,查询就会回传找不到的结果,而 B-tree 的平衡效果,使得 SQL Server 每次在索引内搜寻数据动作时都只会在相同数量的各层索引页内处理,以利精准地找到所需数据。

     

    更优的 Bw (Buzz Word) - tree

    Bw-tree为内存优化索引和数据表带来重大改善,简单来说Bw-tree结构可以更省储存空间(内存)、更有效利用多核心且针对范围(range)和指针(point)搜寻有很高效率。

    Bw-tree结构 (图3)B-tree类似,所有分叶节点依然还是数据页(data page),其他index node只存放key (有顺序) 和下一页指针,且每页都透过一个逻辑指针(PID)串联一起,透过该PID对应Mapping Table即可找到数据存放的物理位置。

    3 Bw-tree 结构。

     

    页面分割

    SQL Server每页可储存8060 bytes数据 (大小为8092 bytes),如果以INT类型的数据行建立索引,数据表每一列数据就需要4 bytes的索引储存空间,假设数据表有2016笔数据 (需 8064 bytes 储存空间),因为索引词条已无法容纳于一页内,则必须进行页面分割,所以会加入两个新索引页面,在现有的根节点页面下移成为分叶层页面,并将原索引页面的一半数据,移至新产生的分叶层页面上,而在上层的页面则成为新的根节点页面,最后则是将每一个分叶层页面的词条写入至新的根节点页面。所以总共使用三个索引页面,一个根节点页面和两个分叶层页面 (这时不需要中继层页面,因为根节点页面可包含全部分叶层页面的词条),所以在搜寻数据时,最多会在两个页面执行,但如果页面分割发生频率过高将严重影响效能,所以设计索引上一定要考虑减少页面分割发生频率。

    Note:页面分割不仅影响效能,同时也会影响交易纪录档案大小,该案例可参考 [SQL SERVER][Memo]页面分割影响事务历史记录档大小

     

    索引类型介绍

    丛集索引

    数据表存在丛集索引,那么数据就会依照丛集索引键值顺序存放,该索引分叶层包含数据页(data page),所以当透过丛集索引搜寻数据即会返回数据真实存放位置,这样的特性即表示一个数据表只能有一个丛集索引,虽然并非每个数据表都一定要有丛集索引,但如有符合以下条件时,建议最好建立:

    1. 大数据表且没有任何非丛集索引 (nonclustered indexes)

    当你要查询相关数据时,如果没有丛集索引,那么就会进行表扫描,将从数据表第一笔扫描到最后一笔数据才能返回相关所需数据。

    2. 针对某些字段常使用范围搜寻

    有了丛集索引就可以避免整个数据表的物理数据排序处理,因为数据已经预先依照丛集索引键值排序过了。

    3. 针对某些字段常使用 group by

    数据要group by需先经过排序处理,而丛集索引将可省下排序处理。

    4. 针对某些字段常使用排序

    因为丛集索引已经排序了相关数据,所以查询一开始就可以避免排序处理。

     

    建立丛集索引键值前需决定丛集索引键值 (相当重要的事),因为数据存放顺序会依照所选择字段来排序(降或升幂),虽然选择丛集索引键值没有一定的标准,但大致上还是方向可循,下面是我自己用来选择丛集索引键值准则:

    1. 排序、群组

    2. 唯一性

    3. 不可 null

    4. 避免宽索引

    5. 数据异动少

    6. 考虑 insert 数据排序 (最小碎片)

    Note:当你定义数据表PK (Primary key)时,SQL Server默认会自动建立丛集索引。

     

    非丛集索引

    非丛集索引不排序或存放任何数据,索引页(index page)上所有分叶节点只存放指针,如果数据表已存在丛集索引,那么该指针将会指向丛集索引,如不存在将指向数据真实存放位置,所以建立丛集和非丛集索引顺序相当重要。

     

    综合索引

    该索引可以有两个以上字段,字段顺序请依照选择性高低摆放 (选择性高越前面),如果查询有需要多字段时即可建立提高效能。

    范例:

    select FirstName,LastName

    from Person.Person

    where FirstName like 'r%' and LastName like '%z'

    使用索引扫描、执行计划成本:0.103029

     

    依照该TSQL建立复合索引:

    create index idx1 on Person.Person(FirstName,LastName)

    改用索引搜寻,执行计划成本降低为0.0082498

    Note:密度和选择性可参考 [SQL SERVER] [Performance]密度和选择性 一文。

     

    单一索引

    该索引只有一个字段,针对单一字段搜寻数据很有用。

     

    范例:

    create index idx2 on Person.Person(FirstName)

       

     

    涵盖索引

    涵盖索引算是使用率最高的索引类型,建立索引时透过include子句来扩充非索引键字段,SQL Server会将非索引键字段存放在索引上的分叶阶层 (不会每一笔索引列都存在),该层级几乎可说是索引叶上的最末层,且include只支持非丛集索引类型,涵盖字段有以下特性:

    1. 索引键不受限 900 byte 限制,因为不会存放在 root 或中继层。

    2. 可包含计算数据行,但数值必须有一定性。

    3. 不能涵盖 text、ntext 和 image 数据类型。

    4. 不能涵盖索引键值。

     

    范例:

    select FirstName,LastName,Title,PersonType

    from Person.Person

    where MiddleName='A' and EmailPromotion>=1

    使用丛集索引扫描、执行计划成本:2.84673

     

    建立涵盖索引

    create index idx3 on Person.Person(MiddleName,EmailPromotion)

    include(FirstName,LastName,Title,PersonType)

    改用索引搜寻、执行计划成本:0.0079515

     

    唯一索引

    该索引可以强制索引键字段具有唯一性,当你定义唯一约束默认会建立唯一非丛集索引,或数据表没有丛集索引且定义PK默认也会会建立唯一丛集索引,该索引一般来说会大幅提高效能 (可以产生很有效的执行计划),如果你确定相关字段具有唯一值,且查询也需要这些字段,那么建立唯一索引绝对不会错,唯一索引特性如下

    1. 可以使用单一或多个字段

    2. 可以为丛集或非丛集 (包含 include)

    3. 索引建立 (或重建) 期间,会确认索引键字段是否有重复值

    4. 数据新增或更新期间,会确认索引键字段是否有重复值

     

    筛选索引

    筛选索引是优化的非丛集索引,但索引弹性相对低,所以实务上实用性较低的,但针对已知且固定的数据子集,建立筛选索引确实可以大大提高查询效能并减少索引使用空间,案例参考 [SQL SERVER][Memo]筛选索引一文。

     

    分割索引

    建立分割数据表并在该数据表上建立索引 (建议包含 (include) 分割数据行)SQL Server默认会使用相同的分割结构(partition scheme)和分割数据行(partition column)自动对索引进行分割,主要是希望索引和数据表对齐(aligned),索引和数据表对齐对效能来说相当重要,分割索引不只可以提高询效能,也可减少索引管理成本,因为你可以针对某区索引碎片执行重建操作,进而减少某种程度的SQL Server停机时间。

     

    数据行存放区索引

    SQL 2012新增的数据行存放区索引主要是提高OLAP效能,储存方式不像以往采取row,而是改成column方式储存,这会大大提高缓冲命中率并减少I/O,同时对于完整扫描作业可以带来极大效能效益,但建立该索引后,数据表会变成唯独,这个限制导致不太适用在OLTP环境中,但开心的事在SQL 2014移除了这项限制,这改善真是大快人心。

     

    范例:SQL 2014数据行存放区索引数据更新测试

    create table mycolumnstore

    (

    c1 int identity(1,1),

    c2 varchar(30),

    c3 date

    )

     

    --建立columnstore index

    create clustered columnstore index cidx_cs

    on mycolumnstore

     

    新增操作

      

     

    更新操作

     

    删除操作

     

     

    内存优化索引

    SQL 2014内存优化索引使用Bw-tree结构,所有逻辑指针都存在内存中,总共有两种非丛集索引类型。

    1. 非丛集哈希 (hash)索引:

    该索引适用指针查阅,大小固定且没有任何页面(page),查询返回的值都是没有排序。

    2. 非丛集非哈希 (hash) 索引:

    该索引适用范围或排序扫描,也适用任何符合SARG查询参数,查询返回的值都会排序。

    范例:

    --建立内存优化数据表

    CREATE TABLE [TransactionHistoryArchive] (

    [TransactionID] [int] NOT NULL

            CONSTRAINT PK_TransactionHistoryArchive primary key NONCLUSTERED HASH WITH (BUCKET_COUNT = 100000),

    [ProductID] [int] NOT NULL,

    [ReferenceOrderID] [int] NOT NULL,

    [ReferenceOrderLineID] [int] NOT NULL,

    [TransactionDate] [datetime] NOT NULL,

    [TransactionType] [nchar](1) NOT NULL,

    [Quantity] [int] NOT NULL,

    [ActualCost] [money] NOT NULL,

    [ModifiedDate] [datetime] NOT NULL index idx1,

          index idx2(TransactionID),

    ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)

     

     

    --新增数据:内存数据表的交易无法跨数据库

    SELECT * INTO mytemp

    FROM AdventureWorks2012.Production.TransactionHistoryArchive

     

    INSERT INTO TransactionHistoryArchive

    SELECT * FROM mytemp

     

    --排序查询

    --good

    SELECT * FROM TransactionHistoryArchive with(index(idx2))

    order by TransactionID

    --bad

    SELECT * FROM TransactionHistoryArchive with(index(PK_TransactionHistoryArchive))

    order by TransactionID

     

    --lookup

    --bad

    SELECT TransactionID,ReferenceOrderID,TransactionType,ActualCost

    FROMTransactionHistoryArchive with(index(idx2))

    where TransactionID=10

    --good

    SELECT TransactionID,ReferenceOrderID,TransactionType,ActualCost

    FROM TransactionHistoryArchive with(index(PK_TransactionHistoryArchive))

    where TransactionID=10

     

    索引设计注意事项

    索引设计基本上需对应数据存取TSQL才能到位,这里提出一些索引设计须注意相关事项让大家参考:

     

    1. 先建立非丛集索引后建立丛集索引

    前面索引类型内容有提到,当一个数据表没有丛集索引时,先建立非丛集索引的分叶层页面指针将指向真实数据位置,如丛集索引已经存在时将指向丛集索引,先建立非丛集索引可以避免当你重建丛集索引时,连带影响非丛集索引一起重建 (须注意索引两次重建问题),这不仅拉长重建索引时间,也增加交易纪录档大小且浪费硬盘空间。

     

    2. 使用索引压缩

    使用索引压缩可以提高缓冲区命中率 (缓冲区可存放更多词条) 并减少I/O和硬盘空间,建立索引时可以善加利用,但由于压缩操作需要使用较多CPU资源,所以须注意CPU资源竞争情况。

     

    索引压缩测试:

    --建立数据表

    create table test1

    (c1 int null,

    c2 varchar(10) null)

    --新增数据

    declare @i int

    set @i=1

    while @i<2016

    begin

    insert into test1 values(@i,null);

    set @i=@i+1;

    end

    --建立非丛集索引不使用压缩

    create nonclustered index nidx_1 on test1

    (c1)

     

    --查看索引页面数(page_count)和其他相关信息,确认压缩所带来的优势

    SELECT o.name,

    ips.index_id,

    ips.partition_number,

    ips.index_type_desc,

    ips.record_count, ips.avg_record_size_in_bytes,

    ips.min_record_size_in_bytes,

    ips.max_record_size_in_bytes,

    ips.page_count, ips.compressed_page_count

    FROM sys.dm_db_index_physical_stats (DB_ID(N'AdventureWorks2012'), OBJECT_ID( N'AdventureWorks2012.dbo.test1'), NULL, NULL, 'DETAILED') ips

    JOIN sys.objects o on o.object_id= ips.object_id

    ORDER BY index_id asc,record_count DESC ;

    页面总数量5,每笔数据平均大小16 (bytes)

     

    --建立非丛集索引并使用页面压缩

    create nonclustered index nidx_2 on test1

    (c1)

    WITH ( DATA_COMPRESSION = PAGE ) ;

    使用页面压缩可以看到每笔数据平均大小从16降低为9.434,页面数量从5降低为3

     

    3. 设定填满因子 (Fill Factor)

    透过设定填满因子可以微调索引效能和储存空间,该因子会决定分叶层页面填满数据的空间百分比 (保留每个页面可用空间),以利未来数据成长使用,主要目的是要减少页面分割发生频率,如设定90 (默认 0)表示只预留10%空间比例,实务上我建议该值依数据表读写特性设定比较有效益,因为设定过低将增加页面分割频率,也造成索引碎片过多增加I/O,进而影响查询效能且容易发生长时间Lock资源情形,但设定过高也会影响数据异动效能,所以建议必须依数据表读写特性设定取得一个平衡值,下面是填满因子建议值:

    a. 只读或静态数据表: 设定 100%

    b. 异动频率很低的数据表: 设定 95%

    c. 异动频率一般的数据表: 设定 85%~90%

    d. 异动频率很高的数据表: 设定 50%-80% 

     

    4. 索引键字段最好用于 join 操作

    Join多个数据表是常见的情况,当建立非丛集索引时最好第一优先考虑这些join字段,或是设定Foreign key约束,这样才能让索引发挥效益并大大改善查询效能。

     

    5. 善用涵盖索引

    涵盖索引include字段不受900 bytes限制,且又可满足查询所需数据字段,即不须额外浪费时间搜寻data page,该索引效益永远比单一字段索引来的高,而且更有弹性。

    案例可以参考 [SQL SERVER]提高动态查询效能

     

    6. 优先考虑选择性高字段

    Distinctwhereorder bygroup bylike子句相关字段最好选择性高,高选择性字段可以让索引更有效益,主要可以让统计值估计更准确。

     

    7. 适时重建索引

    当在数据表中删除一笔数据时,SQL Server必须由索引页中移除该笔数据的索引数据,而这就会导致在索引页中留下空白,由于填补新值的成本太大,所以SQL Server也不会去填补该空白,若在数据表中更新一笔数据时,则SQL Server必须在索引页中搜寻适当的位置并加入,而这也有可能会造成另一段空白。当索引页已满且必须进行分割时,就会产生更多的索引碎片,当碎片过多就会影响查询的效能 (因为跨多个索引页,所以增加 IO 读取),所以当数据表数据异动频繁时,时间一久,就会造成索引不断破碎 (空白太多),这时候建立要执行重建索引操作。

    索引碎片又分两种类型,内部碎片和外部碎片。

    外部碎片:

    由于索引数据都是经过排序的,如果你的分叶层页面(index leaf page)实体排序和查询所要求的逻辑排序不相同时,就会导致SQL Server有额外的工作来返回正确的排序结果,但在大多数的查询情况下,内部碎片并不会太大,但在设计索引上还是得注意排序的需求。

    内部碎片:

    一般来说索引页都会预留一定的空间来存放新增(insert)的数据,因为这可以减少页面分割发生的频率,所以当你在建立或重建索引时,你可以指定填满因子(Fill Factor)来决定一张索引页面可存放多少百分比数据,如果索引页面过于分散,将会拉长查询时间 (跨多索引页面,并增加额外的 IO 读取),而且也会造成你的索引过于肥大 (浪费硬盘空间),请务必减少页面分割发生的频率,因为页面分割这样的动作相当耗费系统资源。

     

    进阶推荐

    若您有兴趣进阶学习,可参考MVP James Fu录制的数据库例行管理系列教学之索引维护篇,除了教学影片,亦提供了简报档下载,都是完全免费的,欢迎多多运用。

    希望以上内容对您的学习有所帮助。

  • Windows 10:全新一代的 Windows

    微软宣布 Windows 10 将提供免费升级

    揭开群组运算与全像摄影 Windows 10 装置神秘面纱

    经过前一晚 Windows 10发表倒数计时,跨平台Windows即将登场 ,微软公司于今日发布了结合各类不同体验的新一代 Windows 系统,开启了更为个人化运算的新纪元,除此之外,微软也发布了两款全新装置,拓展从大屏幕到无屏幕等各类装置上的 Windows 体验。 Windows 10 将在装置上,提供一个更安全、创新与最新的体验。

    Windows 10发表会在线影片回放: http://news.microsoft.com/windows10story/

    Windows 10免费升级服务(附注1)将提供给目前使用Windows 7、Windows 8.1以及Windows Phone 8.1的消费者在第一年可以享受免费升级的服务。

    「Windows 10的推出象征我们将进入以行动优先,云端至上(Mobile First, Cloud First)的世界,开启更加个人化运算的新世代」微软全球执行长Satya Nadella表示。「我们的目标是让目前正在使用 Windows 的 15 亿用户爱上 Windows 10,并让更多用户决定将 Windows 带回家。」

    全新 Windows 10 体验:

    Windows 10:让计算机运算更加个人化

    Windows 10的推出象征着我们将迎来更为个人化运算的新世代,这意味着以人为中心的理念将逐渐代替技术。 在这个新世代中,比起单纯让装置具有行动力,让使用经验具有行动力更重要、而且要无缝的让相同的体验跨到不同装置上。

    用户应能够像与他人互动一样,用语音、手势和目光自然地与科技互动,在这样的情况下如果要提供一个值得信任的使用体验,隐私权保护就扮演着举足轻重的角色。

    在活动上微软展示了Windows 10提供的多种新体验,具体包括:

    Cortana 进驻 PC 和平板计算机

    去年针对Windows Phone推出的Cortana个人数字助理现在也将可以在Windows 10的PC和平板计算机上使用,帮助用户完成事务(附注2)。

    Cortana是用户的个人小助手,能够了解个人的喜好,进而提供个人化推荐、快速搜寻到信息与提醒重要事项,提供用户最想要关注的信息。

    用户可透过交谈或打字自然而轻松与Cortana互动,还可以透过进阶设定来 让 Cortana 更加可靠与同步。


    全新浏览器「Project Spartan」让浏览器为你动起来

    Windows 10未来将推出代号为「Project Spartan」的全新微软浏览器;这款浏览器是以互操作性为设计核心, 该浏览器本身也内建了多项重要功能,提高了可靠性与更佳的搜寻功能。这个浏览器中最先进的功能包括:

    ·         无论是使用键盘还是触控笔,都能直接在网页上注记并与朋友轻松分享,同时提供不受干扰的阅读方式

    ·         无论是上线或是脱机状态,让文章呈现更加简化,加上与Cortana整合可更快速地在在线搜寻内容和完成事务,这些最新的创新全部都可以在Windows 10上体验到。

    Xbox Live 和全新 Xbox App 为 Windows 10 带来全新游戏体验

    Windows 10上的Xbox让玩家和开发人员透过Windows 10计算机和Xbox One体验Xbox Live游戏网络的精华。玩家可以使用 Game DVR 节录、编辑和分享他们最精彩的游戏时刻,以及与多台装置上的朋友畅玩新游戏,与世界各地数百万名玩家之间建立联系。

    Windows 10透过全新DirectX 12应用程序设计界面开发的游戏,无论是在速度、效能和画面上皆有所提升,玩家还能够将游戏直接从Xbox One游戏机存到Windows 10平板计算机或PC中,在家中畅玩(附注3)。

    Windows 10 中的 Office

    Windows 10上的Office通用应用程序(Universal Apps)提供了在多台装置上最佳的触控体验。

    新版Word、Excel、PowerPoint、OneNote和Outlook都是为了在Windows上使用而设计,提供了客熟悉并喜爱的Office体验,透过Office的常见功能,用户可以轻松编辑Word文件。 PowerPoint 中的全新数字笔迹功能可让用户实时为幻灯片添加附注,而藉由 Excel 中针对触控优化的全新控制功能,用户无需使用键盘或鼠标即可轻松建立和更新电子表格。

    目前新版Office桌面软件也正在开发中,微软将在接下来的几个月中分享更多信息。

    今天发布的其他Windows 10功能和创新包括:

    ·         Continuum模式: 在二合一装置上,Windows 10 将可以轻松的感应到转换模式的需求,在键盘和鼠标、触控和平板计算机之间轻松的切换。

    ·         全新的通用应用程序:Windows 10将针对相片、影片、音乐、地图、联络人和讯息以及邮件和行事历提供全新体验的应用程序(实现跨装置一致性)。 这些内建应用程序更新后的设计,将在外观和体验方面在各个应用程序和各种装置上都保持一致。 内容可以经由 OneDrive 储存和同步,可让用户在不同的装置上继续未完成的事务。

    「从Windows 10的各个方面来看,比如体验、作为服务提供以及免费升级,Windows 10并不仅仅是另外一件产品,更是一种持续关系,这种关系能够持续为我们的所有客户创造价值,」微软操作系统部门执行副总裁Terry Myerson说, 「新一代 Windows 代表着我们的承诺,也就是将用户从复杂的技术中解放出来,并帮助他们完成更多重要事情。」

    Windows 10:推动创新,激发全新运算平台

    Windows 10可让客户以一致、熟悉和可兼容的体验使用各种装置(从Xbox到 计算机和手机,再到平板计算机和小工具)和处理各项事务。 Windows 10 适用的装置非常广泛令人难以置信,从物联网中最微小的传感器到世界级企业数据库中的服务器,无所不包。

    有些装置有4吋大小的屏幕、有些到80吋大小的屏幕、还有一些甚至没有屏幕,今日微软公布的两款设备将提供用户难以置信的全新Windows体验。

    Windows 10 Microsoft HoloLens 开启全像摄影未来

    微软利用革命性的例证分享Windows 10如何从以传统装置为中心的运算、转变到更为个人化和人性化的互动。 作为全球首款全像运算平台,Windows 10 包含一系列应用程序开发接口 API,可让开发人员创造现实世界中的全像摄影体验。

    有了Windows 10,全像摄影就是Windows共通应用程序,而所有的Windows共通应用程序也可作为全像摄影运用,这样可实现将3D全像图像放入物理世界中,实现更为个人化和人性化的全新沟通、创建和探索方式。

    为了实现在Windows 10中使用全像摄影的可能性,微软公布了全球最先进的全像计算机。

    ·         Microsoft HoloLens是首款不受约束的全像计算机,无需电线、手机或连接到所需的计算机。

    ·         Microsoft HoloLens配备透明的全像高分辨率镜头和空间声音,可让您用眼睛和耳朵了解周围环境中的全像影像。

    ·         Microsoft HoloLens拥有先进的传感器和新一代片上系统,还配备全新的全像处理单元(HPU)来了解您的行为和周围环境,因此无需电线即可运行,并处理从传感器实时接收的兆字节数据。

    透过在您周围的环境中放置3D全像图,Microsoft HoloLens可让您以新的方式观察现实世界,从而分辨出您看到的事物并了解您的手势和语音代表的内容。 透过将用户置于计算体验的中心,Microsoft HoloLens 可让您创造内容、存取信息、享受娱乐以及用全新有趣的方式沟通。

    全新的 Microsoft Surface Hub 优化了群组的 Windows 10 体验

    Windows 10支持全新的大屏幕装置,可帮助团队在工作场所中共同分享、想象和创造。 透过多点触控和数字笔迹方面的硬件创新以及内建相机、传感器和麦克风,Surface Hub 可以透过 Windows 10、Skype for Business 和 Office 365 提供全新体验,让每个人(无论是远程还是现场)都如同身处在同一个工作空间中。

    具体来说,Surface Hub的功能包括艺术数字白板、实时远程会议、多人共享笔记本电脑、平板或手机共享和编辑屏幕内容的功能,以及针对大屏幕应用程序的平台。 Surface Hub 提供 55 吋和 84 吋两种尺寸,突破了传统会议室应用情境的限制,让团队实现最佳合作。

    新版Windows 10 Technical Preview的PC版将于下周提供给参加Windows Insider Program计划的用户,而Technical Preview手机版也将于2月推出。更多关于 Windows Insider Program计划和 Technical Preview 的信息,请参考:http://preview.windows.com

    附注1需符合硬件和软件要求。不同设备可用的功能将有所不同。某些版本不包含在内。更多详情请上: http://www.windows.microsoft.com

    附注2 Cortana推出时仅在部分市场可使用。

    附注3 Xbox Live功能(包括游戏记录)仅可在Xbox Live支持的国家/ 地区使用于受支持的游戏。详情请参见 http://www.xbox.com/en-US/live/countries。 Direct X12 仅支持部分游戏和图形芯片。 2015 年推出的少数游戏支持跨设备畅玩;其他游戏即将推出该功能。 Xbox One 的多玩家串流技术需要家庭网络连接和 Xbox Live Gold 会员(单独售卖);Gold 会员也需要在Xbox One 使用多玩家模式畅玩。

    关于Windows 10的更多信息,请访问: http://news.microsoft.com/windows10story

  • 从 Web Server 向 Azure WebSites 迁移的利器(Migration Assistant)

    原文地址:http://blogs.technet.com/b/nevin_dongs_blog/archive/2014/12/25/web-server-azure-websites-migration-assistant.aspx

    将Web应用迁移到云端,常见的做法是采用IaaS模式,即创建虚拟机(Virtual Machine,VM)并在上面分别部署Web Server、Database Server、Cache Server、DNS Server等;当访问负荷增大的时候,则增加虚拟机的数量来实现伸缩。

    之前曾讨论过,可以将数据库服务器(Database Server)采用Platform as a Server(PaaS)模式来提供,也有相关的迁移工具来帮助从SQL Server迁移到Azure SQL Database

    Azure网站(WebSites)是一种完全托管的平台即服务 (PaaS) 产品,便于快速高效地构建、部署并扩展企业级 Web 应用。同时,可以支持按需自动缩放(Auto-scaling),灵活支持不同时间段的并发访问负荷,特别是尖峰负荷。此外,可以显著降低运维工作量,而不必过多关注底层虚拟机、操作系统、网络、负载均衡等细节。

    对于Azure网站的更多细节,可以参考:http://www.windowsazure.cn/home/features/web-site/

    可以开发ASP.NET网站并部署到Azure网站,相关步骤可参考:http://www.windowsazure.cn/zh-cn/develop/net/tutorials/web-site-intro-tutorial/

    如果将现有Web应用迁移到Azure网站,可以使用一个开源的辅助工具:Azure Websites Migration Assistant,具体可参考:http://migrate4.azurewebsites.net/

    目前支持从IIS Server迁移到Azure WebSites,其中特别提供了技术兼容性等方面的分析,例如端口绑定(Port Binding)、IIS身份认证、GAC、缓冲池等。如下图,工具将给出分析报告。

    clip_image001

    目前,这个工具只支持从IIS server到Azure WebSites的迁移辅助,而Azure WebSites还支持Java、PHP、Node.js或Python,后续期待工具能够涵盖对这些技术的支持;当然,也可以考虑参考这个工具的思路,开发适合自己需要的迁移辅助工具。

  • 如何写出高效能TSQL -���入浅出SQL Server Relational Engine (含 SQL 2014 in-memory Engine)

    原文地址:http://blogs.technet.com/b/technet_taiwan/archive/2015/01/16/tsql-series-0116.aspx

    简介

    良好的TSQL和正确索引是大幅提高查询效能最快的快捷方式,同时TSQL也是使用SQL Server的核心,任何应用程序想要和SQL Server沟通,都无法避免撰写TSQL,所以各种效能调校方法中,我们认为查询调校是最省成本、最快能感受到效果的方法 (如下图),这一系列文章将为大家介绍如何写出高效能TSQL,以及开发人员必须了解SQL Server相关基本知识和观念,这样才能活用相关技术,并发挥SQL Server无限潜能。

     

     

    SQL Server 关系型引擎

    SQL Server数据库引擎主要有两部分,这我们里不讨论储存引擎(storage engine)架构,而将会着重在关系型引擎。

    由于SQL Server处理查德询过程步骤相当繁琐,当一句TSQL送给SQL Server时,我们须了解关系型引擎是如何工作的,因为每一句TSQL都必须透过关系型引擎分析处理,最后才会透过储存引擎执行并返回用户所需的数据结果集,理解关系型引擎不仅可以帮我们预先避开效能陷阱,同时也有助于我们减少查询调校和除错时间,下面我将说明几个处理关键步骤。

    图一:SQL Server处理查询简单示意

    图二:SQL Server处理查询关键步骤流程图

     

    分析和绑定

    一开始查询优化器会先确认语法正确性,如有错误将会立即返回错误讯息给用户,如果没有错误就会建立分析树并进行对象绑定 (如数据表字段是否存在、数据型别是否正确、函式是否异常..),主要是因为 TSQL 并非程序性语言,它无法告知数据库应该用什么样正确步骤来撷取数据,所以这阶段会帮你处理基本语法优化、数据型别转换,简单来说就是会改写 TSQL,如把 between 转换为 >= and <=,型别比较不一致时,自动增加转换函数来确保数据正确性 (这就可能会大大影响查询效能) group by 位置..等,最后将输出逻辑 (操作) 查询树,后面将会依照所输出逻辑查询树步骤来一一执行。

     

    查询优化

    查询优化几乎可说是最复杂且耗时的阶段 (所以大家要有一点想象力),一开始会先确认计划快取区是否有适当的执行计划,如果没有找到适当执行计划,就会进行一般优化 (如果可以的话),然后再次从计划快取区寻找是否有适当的一般计划,如果存在就会分配相关内存并执行,这是因为不必为只有一种可能执行方法的TSQL进行完整优化,如此一来可以省下编译和建立执行计划时间,因为我们知道查询效能一部分取决于建立执行计划效率 (执行查询时间是产生执行计划时间 + 本身数据查询时间),所以查询优化器并不会寻找最佳执行计划,而是尽可能寻找最低成本 ( CBO 为基础的 CPUI/O 成本) 及传回结果速度最快的执行计划,如果该TSQL有达到一般计划条件的话,那么查询优化器将可不必进行完整优化而浪费不必要时间,下面我简单列出建立一般计划的情况

    1. 只有查询单一数据表,且没有任何 order by or group by

    2. 只有查询单一数据表,且该数据表没有任何索引。

    3. 只有查询单一数据表,且符合 SARG (search argrment) 格式及条件比对使用唯一值 (unique key)

    4. 查询只使用系统默认函示 ( select getdate()..)

    5. 使用 insert..values 只新增单一数据表数据。

    现在我们知道,如果查询语法符合一般计划的情况,那么SQL Server在建立计划时将会省下很多时间,但如果不符合的话,SQL Server将针对该查询撷取所有可用统计值数据(字段和索引),并先从计划快取区寻找是否有符合该查询的执行计划,如果有找适当执行计划的话,就在判断是否需要经过完整优化 (如查询使用了recompile 提示就必须进行完整优化),如果没有找到适当执行计划的话,那么就必须进行完整优化,这个时候查询优化器,会以所输出的逻辑查询树为基准,自我设计各种可能执行的方法,虽然这里会产生多种排列组合,但之前有提过,SQL Server并不会寻找最佳执行计划,因为寻找最佳执行计划所花费时间成本可能还会高出本身查询所需时间成本,所以只会寻找最低成本执行计划。

    为了加速这处理过程,SQL Server将会采取平行处理来建立执行计划,前提是Server有多核心且cost threshold for parallelism and max degree of parallelism两个参数设定正确。

    一般会选择非平行执行计划,但如果非平行计划成本超过平行计划成本,那么SQL Server将会把负载传送给每个可用CPU,这时将会建立平行执行计划,一般来说,在OLTP环境中需特别注意采用平行执行计划的查询,因为大多数都是不良TSQL、不正确索引或索引遗漏..等造成 (发生高 CPU 情况)

    当完整优化后将产生低成本适当的执行计划,这时就会将该计划存放到计划快取区中,并继续下一运行时间。

     

    计划快取和查询执行

    取得相关执行计划后,这时就会将该计划送给储存引擎,由储存引擎来执行该查询并且返回使者所需的数据结果集,这里须注意SQL Server可能会改变当初估计的执行计划,如果有达到以下条件

    1. 所需数据表和字段统计值过时。

    2. 执行期间所触及数据或统计值异动过大。

    3. 非平行执行计划运行时间超过 cost threshold for parallelism 设定值。

     

    如果执行期间数据、统计值异动过大,将会导致发生重新编译,你可以想象在最后一步骤才知道需要重新编译的话,这无疑对效能是一大伤害。

    再来就是计划快取区只保留最常执行的查询计划,太久没执行的查询计划可能会自动清除,底下有几个情况会自动清除计划快取区,并再次发生完整优化处理

    1. 当缓冲池 (buffer pool) 针对另一对象需要更多内存

    2. 当查询计划不被任何联机使用

    3. 当查询计划成本因子为 0

     

    这里简单说明一下计划成本因子,每个执行计划都有该成本因子,每一次执行该执行计划就会自动累加1SQL Server并不会自动递减该成本因子,但如果计划快取区大小达到buffer pool大小50%时,当下一次计划快取区被存取时,这是就会将快取区所有执行计划的成本因子都减1,这时如有成本因子为0的就会被清除掉。

    为了要善用计划快取区,所以我们要尽量避免SQL Server发生内存不足问题,如果你遇到内存压力问题,可以开启optimize for ad hoc workloads (SQL 2008 以后才有) 来减轻内存压力

    -- 开启optimize for ad hoc workloads

    sp_CONFIGURE 'show advanced options',1

    reconfigure

    go

    sp_CONFIGURE 'optimize for ad hoc workloads',1

    reconfigure

    go

    select * from master.sys.configurations

    where name='optimize for ad hoc workloads'

    go

     

    同时我们也要避免在正式环境中手动清除计划快取区 (使用 DBCC FREEPROCCACHE),因为这将导致所有查询都需要重新编译且降低查询效能。

    再来就是我们要尽可能提高执行计划重用率并小心误用错误执行计划所造成效能问题,我简单整理以下 5 点可帮助你执行查询时,提高执行计划重用机率

    1. 避免 ad hoc 查询类型

    2. 动态组 SQL 字符串请使用 sp_executesql 取代 exec

    3. 查询异动值请明确使用参数取代

    4. 尽量使用 SP 但须注意参数探测问题

    5. 尽量使用两字节表示 (dbo.usp_getdate),避免隐式解析

     

    SQL 2014 查询优化器改善 -- 新基数估计算法

    取得最低成本执行计划虽然对大多数情况来说是好的,但并不表示该计划一定是最佳的,为了取得更好执行计划,SQL 2014采用新基数估计算法来进行改善,简单来说就是查询效能会比以前的版本更好,而以前的SQL Server版本都将会遇到旧基数估计演算(Plan Regressions)而造成的效能问题,该问题详细可参考 [SQL SERVER]统计值能吃吗? 一文。

     

    SQL 2014 in-memory OLTP 引擎

    SQL 2014可以让我们建立in-memory数据表来优化OLTP效能,这意味者过去数据表使用硬盘存放并有高资源竞争问题都将获得改善,最大改变就是in-memory数据表将不会有任何latchlock,那你可能会担心交易过程数据一致问题(ACID),这部分在SQL 2014则是使用Multiversion Concurrency Control (MVCC)技术来隔离交易不被干扰,同时也避免lock问题,也可让任何用户随时存取in-memory数据表资源,因为内存中的操作对用户来说都是一闪即逝的过程 (短暂交易最有利),用户几乎不会有任何等待的感觉出现。

    SQL 2014还提供了原生编译的储存程序,透过原生编译的储存程序来存取in-memory数据表可将效能提高是以前版本约50%效益(微软官方数据),主要是因为产生的机器码(machine code),只针对该查询建立应该要执行处理器指令 (无须进一步编译或解释),可以更有效率执行查询,并且更快速得撷取数据,下面我们会使用in-memory OLTP引擎来简单测试不同持久性设定并执行新增数据效能差异。

     

    建立in-memory DBTable (schema_and_data & schema_only)

     

    CREATE DATABASE memoryDB

    ON PRIMARY (

    NAME = [E:\SQLDataFile\memoryDB_data]

    ,FILENAME = 'E:\SQLDataFile\memoryDB_data.mdf'

        )   

    ,FILEGROUP [memoryDB_FG] CONTAINS MEMORY_OPTIMIZED_DATA (

    NAME = [memoryDB_dir]

    ,FILENAME = 'E:\memoryDB_dir'

        )    

    LOG ON (

    NAME = [memoryDB_log]

    ,Filename = 'E:\SQLDataFile\memoryDB_log.ldf'

        )

    GO

     

    CREATE TABLE MemorySchemaAndData

    (

    id int NOT NULL,

    c1 nchar(1) NOT NULL,

    CONSTRAINT PK_MemorySchemaAndData PRIMARY KEY NONCLUSTERED HASH (id) WITH (BUCKET_COUNT = 150000)

    ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_AND_DATA)

     

    CREATE TABLE MemorySchemaOnly

    (

    id int NOT NULL,

    c1 nchar(1) NOT NULL,

    CONSTRAINT PK_MemorySchemaOnly PRIMARY KEY NONCLUSTERED HASH (id) WITH (BUCKET_COUNT = 150000)

    ) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)

     

    进行测试之前我简单说一下建立in-memory数据表注意事项

    Schema_and_dataOLAP系统中,该内存数据表类型最常被使用,透过持久性选项设定,可以确保SQL Server发生崩溃后相关数据表结构和数据依然会保留。

    Schema_only:内存中只存放数据表结构(metadata)SQL Server发生崩溃后相关数据会消失。

    前面我们有提到,in-memory OLTP引擎会建立machine code,所以每一个in-memory数据表都有一颗相对应dll (如下图),当该数据表被加载时,可以避免编译或解释,因此可以更快取得查询数据,同时因为都会被加载到内存中,所以限制每个数据表内存大小也是相当重要的事,微软有提供一个 估算内存大小公式 ,当你要将数据表移转到in-memory数据表时,还请不要忘记该重要环节。

     

    测试新增数据到 in-memory 数据表

    Schema_and_data

     

    DECLARE @step INT

    SET @step = 1

     

    WHILE @step <= 120000

    BEGIN

    INSERT INTO dbo.MemorySchemaAndData

    VALUES (@step, '1'),

    (@step+1, '2'),

    (@step+2, '3'),

    (@step+3, '4'),

    (@step+4, '5')

     

    SET @step = @step + 5

    END

    12万笔约花8秒。

     

    Schema_only

    DECLARE @step INT

    SET @step = 1

     

    WHILE @step <= 120000

    BEGIN

    INSERT INTO dbo.MemorySchemaOnly

    VALUES (@step, '1'),

    (@step+1, '2'),

    (@step+2, '3'),

    (@step+3, '4'),

    (@step+4, '5')

     

    SET @step = @step + 5

    END

     

    12万笔几乎0秒。

     

    确认in-memory数据表数据

    in-memory数据表使用schema_only选项时,新增数据处理几乎没花费任何时间,但我前面有提到过,schema_onlySQL Server发生崩溃后,将不会保留任何数据,所以当你使用该选项时必须要清楚了解该特性,以免发生数据无法复原的惨剧。

     

    重新启动SQL Server DB (仿真 SQL Server 崩溃),并确认in-memory数据表数据状况

     

    Use Master

    go

    ALTER DATABASE memoryDB SET OFFLINE WITH ROLLBACK IMMEDIATE

    GO

    ALTER DATABASE memoryDB SET ONLINE

    GO

    使用Schema_onlyin-memory数据表数据都无保留。

     

    TSQL on Azure

    如有你有使用Azure SQL Database的话,那么在撰写TSQL时需要留意以下几个重点。

    1. 善用数据表值参数

    SQL 2014有加强数据表值参数(SQL Azure 也一样),就是数据表值参数可以使用索引来提高查询效能,以前大家可能比较常用temp table来处理元数据,但在Azure上需要当心使用过多的tempdb资源,毕竟tempdb只有一个 (大家共享),所以当使用过多tempdb资源时,Azure可能会自动切断联机,所以建议使用数据表值参数取代temp数据表来处理元数据。

    2. 减少数据网络来回次数

    由于网络质量我们无法掌握,所以一定要减少数据在AzureClient之间的往来次数,同时也要建立一套安全retry机制,基本上都建议采取批处理 (如一次捞所需的数据结果集),少用row by row方式 (这也增加 Azure 费用成本) 来查询数据或进行数据异动 (c ursor),且所有TSQL请使用try.. catch包起来,如遇到问题 (如网络断线..)才可以有相对应处理方法。

    3. 善用快取

    可以在数据表中新增 rowversion 字段,这样我们就可以轻易使用该字段(注意该字段不建议成为索引键值)来判断上次读取数据列后,数据列中任何值是否有改变,如果没有改变的话就读取本地快取数据,否则就读取Azure上数据,这不仅可以大幅提高效能,同时也可以省下不少 Azure 费用成本。