前言

上一节中,大家描述了Splay的着力操作rotate与splay
本节小编会教我们怎么样用那七个函数完成各样强大的成效
为了有利于讲解,我们拿这道题做例题来稳步分析

原因:

 

   
此前曾经写过一篇关于列存款和储蓄索引的简介http://www.cnblogs.com/wenBlog/p/4970493.html,很粗大劣但是基本评释了列存款和储蓄索引的便宜。为了更好的掌握列存款和储蓄索引,接下去大家一起经过列存款和储蓄索引与历史观的行存款和储蓄索引地比较20第114中学的列存款和储蓄索引带来了怎么改正。由于已经重重介绍列存款和储蓄,因此那里自身仅就质量的勘误实行重点表达。

选用splay完结各样功用

率先,我们须求定义一些事物

测试场景

   
小编创造了多少个测试,尽量确认保障测试环境防止来自外界的重负载进而影响到结果。测试结果依照三个单身的表,分别是:

  • FactTransaction_ColumnStore
    这么些表仅有三个聚集列存款和储蓄索引,由于列存储索引的限量,该表不再有别的索引。
  • FactTransaction_RowStore
    该表将包罗三个聚集索引和多少个非聚集列存款和储蓄索引和贰个非聚集行存储索引。

   
首先小编用剧本文件创造表和目录,然后用30m行数据填充到四个表中。由于有着的测试自身都制定了最大并行度的hint
,因而可以钦定内核数量来询问。

各样指针

    struct node
    {
        int v;//权值
        int fa;//父亲节点
        int ch[2];//0代表左儿子,1代表右儿子
        int rec;//这个权值的节点出现的次数
        int sum;//子节点的数量
    };
    int pointnum,tot;//pointnum代表算上重复的有多少节点,tot表示不算重复的有多少节点

测试1-填充表

  
为了更好地质度量试,四个表由列存款和储蓄索引构成,而另3个表仅有行存款和储蓄索引构成。填充数据来源于另三个表’FactTransaction’。

IO 和时间总结

 

Table 'FactTransaction_ColumnStore'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'FactTransaction'. Scan count 1, logical reads 73462, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

  (30000000 row(s) affected)

SQL Server Execution Times:  CPU time = 98204 ms,  elapsed time = 109927 ms.

Table ' FactTransaction_RowStore '. Scan count 0, logical reads 98566047, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'FactTransaction'. Scan count 1, logical reads 73462, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 (30000000 row(s) affected)

SQL Server Execution Times:  CPU time = 111375 ms,  elapsed time = 129609 ms.

 

rotate

观看测试
表名 填充时间 逻辑读
FacTransaction_ColumnStore 1.49 mins 0
FacTransaction_RowStore 2.09 mins 98566047

 

splay

那八个函数就不讲了,后面早已讲的挺详细了

测试2-相比较搜索

   注意那里在行存款和储蓄索引上小编钦命表的hint,迫使表通过索引查找。

-- Comparing Seek.... 
SET Statistics IO,TIME ON

Select CustomerFK
From [dbo].FactTransaction_RowStore WITH(FORCESEEK)
Where transactionSK = 4000000
OPTION (MAXDOP 1)

Select CustomerFK
From [dbo].FactTransaction_ColumnStore  
Where transactionSK = 4000000
OPTION (MAXDOP 1)

SET Statistics IO,TIME OFF

 

IO 和岁月总括

Table 'FactTransaction_RowStore'. Scan count 0, logical reads 3, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:    CPU time = 0 ms,  elapsed time = 0 ms.

Table 'FactTransaction_ColumnStore'. Scan count 1, logical reads 714, physical reads 0, read-ahead reads 2510, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:    CPU time = 0 ms,  elapsed time = 83 ms.

 

推行陈设

图片 1

插入

基于前边讲的,大家在插入三个数之后,必要将其旋转到根
故而insert函数能够那样写

inline void insert(int v)
{
    int p=build(v);//p代表插到了哪里
    splay(p,root);
}

那么build函数怎么写啊?
当那棵树已经远非节点的时候,大家一贯新建三个节点就好

inline int newpoint(int v,int fa)//v:权值;fa:它的爸爸是谁
{
    tree[++tot].fa=fa;
    tree[tot].v=v;
    tree[tot].sum=tree[tot].rec=1;
    return tot;
}

当这可树有节点的时候,大家依照二叉查找树的性子,不断向下走,直到找到叁个得以插入的点,注目的在于走的时候必要更新一个种种节点的sum值

int build(int v)
{
    pointnum++;
    if(tot==0){root=1;newpoint(v,0);}
    else
    {
        int now=root;
        while(1)
        {
            tree[now].sum++;
            if(tree[now].v==v){tree[now].rec++;return now;}//出现过
            int nxt=v<tree[now].v?0:1;
            if(!tree[now].ch[nxt])
            {
                newpoint(v,now);
                tree[now].ch[nxt]=tot;
                return tot;
            }
            now=tree[now].ch[nxt];
        }
    }
    return 0;
}
观测测试2

正如上海教室所示,行存款和储蓄索引表的索引查找远比列存款和储蓄索引表查询快的多。那至关心器重要归因于二〇一五的sqlserver不协理聚集列存储索引的目录查找。执行布置比较图中三个是索引围观导致越多的逻辑读,由此造成了质量的骤降。

表名 索引类型 逻辑读 运行时间
FacTransaction_ColumnStore Column 714 83 ms
FacTransaction_RowStore Row 3 0 ms

 

删除

删去的意义是:删除权值为v的节点
大家简单想到:大家得以先找到他的地方,再把那么些节点删掉

int find(int v)
{
    int now=root;
    while(1)
    {
        if(tree[now].v==v)   {splay(now,root);return now;}
        int nxt=v<tree[now].v?0:1;
        if(!tree[now].ch[nxt])return 0;
        now=tree[now].ch[nxt];
    }
}

其一函数能够找到权值为v的节点的岗位,比较好掌握,注意别忘记把找到的节点splay到根
别的大家还索要三个完完全全剔除的函数

inline void dele(int x)
{
    tree[x].sum=tree[x].v=tree[x].rec=tree[x].fa=tree[x].ch[0]=tree[x].ch[1]=0;
    if(x==tot)  tot--;
}

接下去的天职便是何许才能担保删除节点后整棵树还满意二叉查找树的性情
小心:大家在寻觅完三个节点的时候已经将她团团转到根了,所以他左手一定都比他小,除此之外没有比她小的节点了(不然还要考虑他阿爸比他小的景观)

那么此时会现出三种情景

  • 权值为v的节点已经面世过
    这时候直接把他的rec和sum加上1就好
  • 本节点没有左外孙子
    直白把她的右孙子设置成根
  • 既有左孙子,又有右孙子
    在它的左外孙子中找到最大的,旋转到根,把它的右外甥当作根(也正是它最大的左外孙子)的右外孙子

说到底把那一个节点删掉就好

void pop(int v)
{
    int deal=find(v);
    if(!deal)   return ;
    pointnum--;
    if(tree[deal].rec>1){tree[deal].rec--;tree[deal].sum--;return ;}
    if(!tree[deal].ch[0])    root=tree[deal].ch[1],tree[root].fa=0;
    else
    {
        int le=tree[deal].ch[0];
        while(tree[le].ch[1])    le=tree[le].ch[1];
        splay(le,tree[deal].ch[0]);
        int ri=tree[deal].ch[1];
        connect(ri,le,1);connect(le,0,1);
        update(le);
    }
    dele(deal);
}

Test 3 – Comparing SCAN

  
注意这一次自身钦点的hint都是索引围观,当然列存款和储蓄索引上优化器默许为索引围观。

-- Comparing Scan.... 
SET Statistics IO,TIME ON

Select CustomerFK
From [dbo].FactTransaction_RowStore WITH(FORCESCAN)
Where transactionSK = 4000000
OPTION (MAXDOP 1)

Select CustomerFK
From [dbo].FactTransaction_ColumnStore WITH(FORCESCAN)
Where transactionSK = 4000000
OPTION (MAXDOP 1)

SET Statistics IO,TIME OFF

 

IO 和时间总结

Table 'FactTransaction_RowStore'. Scan count 1, logical reads 12704, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
  CPU time = 32 ms,  elapsed time = 22 ms.

Table 'FactTransaction_ColumnStore'. Scan count 1, logical reads 714, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:
  CPU time = 0 ms,  elapsed time = 2 ms. 

 

实践计划

图片 2

查询x数的排行

其一差不离,假使大家找到了权值为x的节点,那么答案正是他的左子树的大小+1
不然的话依据二叉查找树的性质不断的向下走就足以,注意要是本次是向右走的话答案供给添加它左子树的尺寸和这几个节点的rec值

int rank(int v)// 查询值为v的数的排名 
{
    int ans=0,now=root;
    while(1)
    {
        if(tree[now].v==v)    return ans+tree[tree[now].ch[0]].sum+1;
        if(now==0)  return 0;
        if(v<tree[now].v)    now=tree[now].ch[0];
        else                 ans+=tree[tree[now].ch[0]].sum+tree[now].rec,now=tree[now].ch[1];
    }
    if(now)    splay(now,root);
    return 0;
}
着眼测试3

  
正如以前提到的,索引扫描列存款和储蓄要比行存款和储蓄快,俩个逻辑读和平运动转时刻注解列存储索引在大表扫描上是更优的艺术,因而更适合于数据仓库的表。

表名 索引类型 逻辑读 运行时间
FacTransaction_ColumnStore Column 714 2 ms
FacTransaction_RowStore Row 12704 22 ms

 

查询排行为x的数

以此操作便是地点十二分操作的逆向操作
用used变量记录该节点以及它的左子树某些许节点
若是x>左子树的数额且< used,那么当前节点的权值正是答案
否则依照二叉查找树的质量继续向下走
一如既往令人瞩目在向右走的时候要更新x

int arank(int x)//查询排名为x的数是什么 
{
    int now=root;
    while(1)
    {
        int used=tree[now].sum-tree[tree[now].ch[1]].sum;
        if(x>tree[tree[now].ch[0]].sum&&x<=used)    break;
        if(x<used)    now=tree[now].ch[0];
        else    x=x-used,now=tree[now].ch[1];
    }
    splay(now,root);
    return tree[now].v;
}

测试4-聚合查询

    测试行存款和储蓄表使用基于聚集索引。

SET Statistics IO,TIME ON

Select CustomerFK,BrandFK, Count(*)
From [dbo].[FactTransaction_RowStore] WITH(INDEX=RowStore_FactTransaction)
Group by CustomerFK,BrandFK
OPTION (MAXDOP 4)

 

   测试行存款和储蓄表,使用CustomerFK 和BrandFK的目录。(覆盖索引)

Select CustomerFK,BrandFK, Count(*)
From [dbo].[FactTransaction_RowStore] WITH(INDEX=RowStore_CustomerFK_BrandFK)
Group by CustomerFK,BrandFK
OPTION (MAXDOP 4)

 

    测试行存款和储蓄索引使用CustomerFK 和BrandFK的列存款和储蓄索引(覆盖索引)

Select CustomerFK,BrandFK, Count(*) From [dbo].[FactTransaction_RowStore] WITH(INDEX=ColumnStore_CustomerFK_BrandFK) Group by CustomerFK,BrandFK OPTION (MAXDOP 4)

Test on the columnstore table using the Clustered Index.

Select CustomerFK,BrandFK, Count(*)
From [dbo].[FactTransaction_ColumnStore]
Group by CustomerFK,BrandFK
OPTION (MAXDOP 4)

SET Statistics IO,TIME OFF

 

求x的前驱

那几个更易于,我们得以保险二个ans变量,然后对整棵树实行遍历,同时更新ans

int lower(int v)// 小于v的最大值 
{
    int now=root;
    int ans=-maxn;
    while(now)
    {
        if(tree[now].v<v&&tree[now].v>ans)    ans=tree[now].v;
        if(v>tree[now].v)    now=tree[now].ch[1];
        else    now=tree[now].ch[0];
    }
    return ans;
}
IO 和岁月计算

    使用基于聚集索引查询行存款和储蓄的表。

Table 'FactTransaction_RowStore'. Scan count 5, logical reads 45977, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
  Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:  CPU time = 9516 ms,  elapsed time = 2645 ms.

 

   使用行存储的非聚集索引测试行存款和储蓄表。(覆盖索引)

Table 'FactTransaction_RowStore'. Scan count 5, logical reads 71204, physical reads 0, read-ahead reads 2160, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:  CPU time = 5343 ms,  elapsed time = 1833 ms.

 

 

   使用非聚集列存款和储蓄索引测试行存款和储蓄表。(覆盖索引)

Table 'FactTransaction_RowStore'. Scan count 4, logical reads 785, physical reads 7, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:  CPU time = 141 ms,  elapsed time = 63 ms.

 

    使用聚集索引测试列存储表。

Table 'FactTransaction_ColumnStore'. Scan count 4, logical reads 723, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

SQL Server Execution Times:  CPU time = 203 ms,  elapsed time = 118 ms.

 

求x的后继

那几个和上一个一如既往,就不细讲了

int upper(int v)
{
    int now=root;
    int ans=maxn;
    while(now)
    {
        if(tree[now].v>v&&tree[now].v<ans)    ans=tree[now].v;
        if(v<tree[now].v)    now=tree[now].ch[0];
        else    now=tree[now].ch[1];
    }
    return ans;
}

总体代码:

#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e6+10;
const int maxn=0x7fffff;
inline char nc()
{
    static char buf[MAXN],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
    char c=nc();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=nc();}
    return x*f;
}
struct SPLAY
{
    #define root tree[0].ch[1]
    struct node
    {
        int v,fa,ch[2],rec,sum;
    };
    node tree[MAXN];
    int pointnum,tot;
    SPLAY(){pointnum=tot=0;}
    int iden(int x){return tree[tree[x].fa].ch[0]==x?0:1;}
    inline void connect(int x,int fa,int how){tree[x].fa=fa;tree[fa].ch[how]=x;}
    inline void update(int x){tree[x].sum=tree[tree[x].ch[0]].sum+tree[tree[x].ch[1]].sum+tree[x].rec;}
    inline void rotate(int x)
    {
        int y=tree[x].fa;
        int R=tree[y].fa;
        int Rson=iden(y);
        int yson=iden(x);
        int b=tree[x].ch[yson^1];
        connect(b,y,yson);
        connect(y,x,yson^1);
        connect(x,R,Rson);
        update(y);update(x);
    }
    void splay(int pos,int to)// 把编号为pos的节点旋转到编号为to的节点 
    {
        to=tree[to].fa;
        while(tree[pos].fa!=to)
        {
            if(tree[tree[pos].fa].fa==to)    rotate(pos);
            else if(iden(tree[pos].fa)==iden(pos))    rotate(tree[pos].fa),rotate(pos);
            else    rotate(pos),rotate(pos);
        }
    }
    inline int newpoint(int v,int fa)//
    {
        tree[++tot].fa=fa;
        tree[tot].v=v;
        tree[tot].sum=tree[tot].rec=1;
        return tot;
    }
    inline void dele(int x)
    {
        tree[x].ch[0]=tree[x].ch[1]=0;
        if(x==tot)  tot--;
    }
    int find(int v)
    {
        int now=root;
        while(1)
        {
            if(tree[now].v==v)   {splay(now,root);return now;}
            int nxt=v<tree[now].v?0:1;
            if(!tree[now].ch[nxt])return 0;
            now=tree[now].ch[nxt];
        }
    }
    int build(int v)
    {
        pointnum++;
        if(tot==0){root=1;newpoint(v,0);}
        else
        {
            int now=root;
            while(1)
            {
                tree[now].sum++;
                if(tree[now].v==v){tree[now].rec++;return now;}//出现过
                int nxt=v<tree[now].v?0:1;
                if(!tree[now].ch[nxt])
                {
                    newpoint(v,now);
                    tree[now].ch[nxt]=tot;
                    return tot;
                }
                now=tree[now].ch[nxt];
            }
        }
        return 0;
    }
    inline void insert(int v)
    {
        int p=build(v);//p代表插到了哪里
        splay(p,root);
    }
    void pop(int v)
    {
        int deal=find(v);
        if(!deal)   return ;
        pointnum--;
        if(tree[deal].rec>1){tree[deal].rec--;tree[deal].sum--;return ;}
        if(!tree[deal].ch[0])    root=tree[deal].ch[1],tree[root].fa=0;
        else
        {
            int le=tree[deal].ch[0];
            while(tree[le].ch[1])    le=tree[le].ch[1];
            splay(le,tree[deal].ch[0]);
            int ri=tree[deal].ch[1];
            connect(ri,le,1);connect(le,0,1);
            update(le);
        }
        dele(deal);
    }
    int rank(int v)// 查询值为v的数的排名 
    {
        int ans=0,now=root;
        while(1)
        {
            if(tree[now].v==v)    return ans+tree[tree[now].ch[0]].sum+1;
            if(now==0)  return 0;
            if(v<tree[now].v)    now=tree[now].ch[0];
            else                 ans+=tree[tree[now].ch[0]].sum+tree[now].rec,now=tree[now].ch[1];
        }
        if(now)    splay(now,root);
        return 0;
    }
    int arank(int x)//查询排名为x的数是什么 
    {
        int now=root;
        while(1)
        {
            int used=tree[now].sum-tree[tree[now].ch[1]].sum;
            if(x>tree[tree[now].ch[0]].sum&&x<=used)    break;
            if(x<used)    now=tree[now].ch[0];
            else    x=x-used,now=tree[now].ch[1];
        }
        splay(now,root);
        return tree[now].v;
    }
    int lower(int v)// 小于v的最大值 
    {
        int now=root;
        int ans=-maxn;
        while(now)
        {
            if(tree[now].v<v&&tree[now].v>ans)    ans=tree[now].v;
            if(v>tree[now].v)    now=tree[now].ch[1];
            else    now=tree[now].ch[0];
        }
        return ans;
    }
    int upper(int v)
    {
        int now=root;
        int ans=maxn;
        while(now)
        {
            if(tree[now].v>v&&tree[now].v<ans)    ans=tree[now].v;
            if(v<tree[now].v)    now=tree[now].ch[0];
            else    now=tree[now].ch[1];
        }
        return ans;
    }
}s;
int main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #else
    #endif
    int n=read();
    while(n--)
    {
        int opt=read(),x=read();
        if(opt==1)    s.insert(x);
        else if(opt==2)    s.pop(x);
        else if(opt==3)    printf("%d\n",s.rank(x));
        else if(opt==4)    printf("%d\n",s.arank(x));
        else if(opt==5)    printf("%d\n",s.lower(x));
        else if(opt==6)    printf("%d\n",s.upper(x));
    }
} 

由来,splay最常用的三种函数就一挥而就了,
上面来看几道裸题

举行安顿

图片 3

例题

不知情怎么,作者的splay跑的专门快,可能是脸太好了吧

观测测试4

 

  
那里才是列存款和储蓄索引开头“闪耀”的位置。七个列存款和储蓄索引的表查询要比守旧的航索引在逻辑读和平运动作时刻上质量好得多。

表名 索引使用 索引类型 逻辑读 运行时间
FacTransaction_ColumnStore ClusteredColumnStore Column 717 118
FacTransaction_RowStore RowStore_FactTransaction Row 45957 2645
FacTransaction_RowStore RowStore_CustomerFK_BrandFK Row 71220 1833
FacTransaction_RowStore ColumnStore_CustomerFK_BrandFK Column 782 63

 

洛谷P2234 [HNOI2002]营业额总结

http://www.cnblogs.com/zwfymqz/p/7896128.html

测试5-相比立异(数据子集)

   那几个测试中,作者将革新少于100m行数据,占总额据的27分之一。

SET Statistics IO,TIME ON

Update [dbo].[FactTransaction_ColumnStore]
Set    TransactionAmount = 100
Where  CustomerFK = 112
OPTION (MAXDOP 1)

Update [dbo].[FactTransaction_RowStore]
Set    TransactionAmount = 100
Where  CustomerFK = 112

OPTION (MAXDOP 1)

SET Statistics IO,TIME OFF

 

洛谷P2286 [HNOI2004]宠物收养场

http://www.cnblogs.com/zwfymqz/p/7895794.html

IO 和时间总括
 
Table 'FactTransaction_ColumnStore'. Scan count 2, logical reads 2020, physical reads 0, read-ahead reads 2598, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(913712 row(s) affected)

SQL Server Execution Times:  CPU time = 27688 ms,  elapsed time = 37638 ms.

Table 'FactTransaction_RowStore'. Scan count 1, logical reads 2800296, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(913712 row(s) affected)

SQL Server Execution Times:  CPU time = 6812 ms,  elapsed time = 6819 ms.

 

执行布署

图片 4

观测测试5

  在那种情景下 ,列存款和储蓄索引的表要比行存款和储蓄的翻新慢的多。

表名 索引类型 逻辑读 运行时间
FacTransaction_ColumnStore Column 2020 37638 ms
FacTransaction_RowStore Row 2800296 6819 ms

 

   
注意对于行存款和储蓄表逻辑读照旧要比行存款和储蓄的要多众多。这是归因于列存储索引的压缩比率更高,由此占有更少的内部存款和储蓄器。

总结

   
列存款和储蓄索引(包括聚集和非聚集)提供了大气的优势。不过在数据仓库上应用依然要搞好准备工作。一种适于地运用处境是非聚集索引不可能被更新且禁止使用对底层表的立异。假使是伟大且并未分区的表,可能存在一个标题,整个表的目录每回都会被重建,因而只要表是巨大的则禁止行使列存款和储蓄索引。由此必供给有好的分区策略来支撑那种索引。

   有多少个利用列存款和储蓄索引的地点:事实表的聚合、法斯特 Track Data Warehouse
Servers、妥善环境SSAS的Cube…