聚集索引和费聚集索引

如果你的数据库中某一个表中的数据满足以下几个条件,那么你就要考虑创建分区表了。
    1、数据库中某个表中的数据很多。很多是什么概念?一万条?两万条?还是十万条、一百万条?这个,我觉得是仁者见仁、智者见智的问题。当然数据表中的数据多到查询时明显感觉到数据很慢了,那么,你就可以考虑使用分区表了。如果非要我说一个数值的话,我认为是100万条。
    2、但是,数据多了并不是创建分区表的惟一条件,哪怕你有一千万条记录,但是这一千万条记录都是常用的记录,那么最好也不要使用分区表,说不定会得不偿失。只有你的数据是分段的数据,那么才要考虑到是否需要使用分区表。
    3、什么叫数据是分段的?这个说法虽然很不专业,但很好理解。比如说,你的数据是以年为分隔的,对于今年的数据而言,你常进行的操作是添加、修改、删除和查询,而对于往年的数据而言,你几乎不需要操作,或者你的操作往往只限于查询,那么恭喜你,你可以使用分区表。换名话说,你对数据的操作往往只涉及到一部分数据而不是所有数据的话,那么你就可以考虑什么分区表了。
    那么,什么是分区表呢?
    简单一点说,分区表就是将一个大表分成若干个小表。假设,你有一个销售记录表,记录着每个每个商场的销售情况,那么你就可以把这个销售记录表按时间分成几个小表,例如说5个小表吧。2009年以前的记录使用一个表,2010年的记录使用一个表,2011年的记录使用一个表,2012年的记录使用一个表,2012年以后的记录使用一个表。那么,你想查询哪个年份的记录,就可以去相对应的表里查询,由于每个表中的记录数少了,查询起来时间自然也会减少。
    但将一个大表分成几个小表的处理方式,会给程序员增加编程上的难度。以添加记录为例,以上5个表是独立的5个表,在不同时间添加记录的时候,程序员要使用不同的SQL语句,例如在2011年添加记录时,程序员要将记录添加到2011年那个表里;在2012年添加记录时,程序员要将记录添加到2012年的那个表里。这样,程序员的工作量会增加,出错的可能性也会增加。
    使用分区表就可以很好的解决以上问题。分区表可以从物理上将一个大表分成几个小表,但是从逻辑上来看,还是一个大表。
    接着上面的例子,分区表可以将一个销售记录表分成五个物理上的小表,但是对于程序员而言,他所面对的依然是一个大表,无论是2010年添加记录还是2012年添加记录,对于程序员而言是不需要考虑的,他只要将记录插入到销售记录表——这个逻辑中的大表里就行了。SQL Server会自动地将它放在它应该呆在的那个物理上的小表里。
    同样,对于查询而言,程序员也只需要设置好查询条件,OK,SQL Server会自动将去相应的表里查询,不用管太多事了。
    这一切是不是很诱人?
    的确,那么我们就可以开始动手创建分区表了。
    第一、创建分区表的第一步,先创建数据库文件组,但这一步可以省略,因为你可以直接使用PRIMARY文件。但我个人认为,为了方便管理,还是可以先创建几个文件组,这样可以将不同的小表放在不同的文件组里,既便于理解又可以提高运行速度。创建文件组的方法很简单,打开SQL Server Management Studio,找到分区表所在数据库,右键单击,在弹出的菜单里选择“属性”。然后选择“文件组”选项,再单击下面的“添加”按钮,如下图所示:
 
 
    第二,创建了文件组之后,还要再创建几个数据库文件。为什么要创建数据库文件,这很好理解,因为分区的小表必须要放在硬盘上,而放在硬盘上的什么地方呢?当然是文件里啦。再说了,文件组中没有文件,文件组还要来有啥用呢?还是在上图的那个界面,选择“文件”选项,然后添加几个文件。在添加文件的时候要注意以下几点:
    1、不要忘记将不同的文件放在文件组中。当然一个文件组中也可以包含多个不同的文件。
    2、如果可以的话,将不同的文件放在不同的硬盘分区里,最好是放在不同的独立硬盘里。要知道IQ的速度往往是影响SQL Server运行速度的重要条件之一。将不同的文件放在不同的硬盘上,可以加快SQL Server的运行速度。
    在本例中,为了方便起见,将所有数据库文件都放在了同一个硬盘下,并且每个文件组中只有一个文件。如下图所示。
 
    第三、创建一个分区函数。这一步是必须的了,创建分区函数的目的是告诉SQL Server以什么方式对分区表进行分区。这一步必须要什么SQL脚本来完成。以上面的例子,我们要将销售表按时间分成5个小表。假设划分的时间为:
    第1个小表:2010-1-1以前的数据(不包含2010-1-1)。
    第2个小表:2010-1-1(包含2010-1-1)到2010-12-31之间的数据。
    第3个小表:2011-1-1(包含2011-1-1)到2011-12-31之间的数据。
    第4个小表:2012-1-1(包含2012-1-1)到2012-12-31之间的数据。
    第5个小表:2013-1-1(包含2013-1-1)之后的数据。
    那么分区函数的代码如下所示:
view plaincopy to clipboardprint?
CREATE PARTITION FUNCTION partfunSale (datetime)   
AS RANGE RIGHT FOR VALUES ('20100101','20110101','20120101','20130101')  
view plaincopy to clipboardprint?
CREATE PARTITION FUNCTION partfunSale (datetime)  
AS RANGE RIGHT FOR VALUES ('20100101','20110101','20120101','20130101') 
CREATE PARTITION FUNCTION partfunSale (datetime)
AS RANGE RIGHT FOR VALUES ('20100101','20110101','20120101','20130101')
    其中:
    1、CREATE PARTITION FUNCTION意思是创建一个分区函数。
    2、partfunSale为分区函数名称。
    3、AS RANGE RIGHT为设置分区范围的方式为Right,也就是右置方式。
    4、FOR VALUES ('20100101','20110101','20120101','20130101')为按这几个值来分区。
    这里需要说明的一下,在Values中,'20100101'、'20110101'、'20120101'、'20130101',这些都是分区的条件。“ 20100101”代表2010年1月1日,在小于这个值的记录,都会分成一个小表中,如表1;而小于或等于'20100101'并且小于'20110101'的值,会放在另一个表中,如表2。以此类推,到最后,所有大小或等于'20130101'的值会放在另一个表中,如表5。
    也许有人会问,为什么值“ 20100101”会放在表2中,而不是表1中呢?这是由AS RANGE RIGHT中的RIGHT所决定的,RIGHT的意思是将等于这个值的数据放在右边的那个表里,也就是表2中。如果您的SQL语句中使用的是Left而不是RIGHT,那么就会放在左边的表中,也就是表1中。
    第四、创建一个分区方案。分区方案的作用是将分区函数生成的分区映射到文件组中去。分区函数的作用是告诉SQL Server,如何将数据进行分区,而分区方案的作用则是告诉SQL Server将已分区的数据放在哪个文件组中。分区方案的代码如下所示:
view plaincopy to clipboardprint?
CREATE PARTITION SCHEME partschSale   
AS PARTITION partfunSale   
TO (   
    Sale2009,   
    Sale2010,   
    Sale2011,   
    Sale2012,   
    Sale2013)  
view plaincopy to clipboardprint?
CREATE PARTITION SCHEME partschSale  
AS PARTITION partfunSale  
TO (  
    Sale2009,  
    Sale2010,  
    Sale2011,  
    Sale2012,  
    Sale2013) 
CREATE PARTITION SCHEME partschSale
AS PARTITION partfunSale
TO (
 Sale2009,
 Sale2010,
 Sale2011,
 Sale2012,
 Sale2013)
    其中:
    1、CREATE PARTITION SCHEME意思是创建一个分区方案。
    2、partschSale为分区方案名称。
    3、AS PARTITION partfunSale说明该分区方案所使用的数据划分条件(也就是所使用的分区函数)为partfunSale。
    4、TO后面的内容是指partfunSale分区函数划分出来的数据对应存放的文件组。
    到此为止,分区函数和分区方案就创建完毕了。创建后的分区函数和分区方案在数据库的“存储”中可以看到,如下图所示:
 
    最后,创建分区表,创建方式和创建普遍表类似,如下所示:
view plaincopy to clipboardprint?
CREATE TABLE Sale(   
    [Id] [int] IDENTITY(1,1) NOT NULL,   
    [Name] [varchar](16) NOT NULL,   
    [SaleTime][datetime] NOT NULL   
) ON partschSale([SaleTime])  
view plaincopy to clipboardprint?
CREATE TABLE Sale(  
    [Id] [int] IDENTITY(1,1) NOT NULL,  
    [Name] [varchar](16) NOT NULL,  
    [SaleTime][datetime] NOT NULL  
) ON partschSale([SaleTime]) 
CREATE TABLE Sale(
 [Id] [int] IDENTITY(1,1) NOT NULL,
 [Name] [varchar](16) NOT NULL,
 [SaleTime][datetime] NOT NULL
) ON partschSale([SaleTime])
    其中:
    1、CREATE TABLE 意思是创建一个数据表。
    2、Sale为数据表名。
    3、()中为表中的字段,这里的内容和创建普通数据表没有什么区别,惟一需要注意的是不能再创建聚集索引了。道理很简单,聚集索引可以将记录在物理上顺序存储的,而分区表是将数据分别存储在不同的表中,这两个概念是冲突的,所以,在创建分区表的时候就不能再创建聚集索引了。
    4、ON partschSale()说明使用名为partschSale的分区方案。
    5、partschSale()括号中为用于分区条件的字段是SaleTime。
    OK,一个物理上是分离的,逻辑上是一体的分区表就创建完毕了。查看该表的属性,可以看到该表已经属于分区表了。
 

本文出自 “无双城” 博客,谢绝转载!

<think>好的,用户想了解聚集索引聚集索引的区别。我需要先回忆一下数据库索引的基础知识,确保自己理解正确。首先,聚集索引应该表的物理存储顺序有关,而非聚集索引则是独立的结构。 接下来,我应该整理两者的定义。聚集索引决定了数据在磁盘上的排列方式,所以每个表只能有一个。而非聚集索引是单独的,可以有多个。需要确认这个点是否正确,比如SQL Server确实是这样,但其他数据库比如MySQL的InnoDB中,聚集索引是主键,如果没有主键则会选其他唯一索引,所以可能有所不同,但用户可能指的是通用情况,还是以常见数据库为例。 然后要比较存储结构。聚集索引的叶子节点直接存数据行,而非聚集索引的叶子节点存的是指向数据的指针或者聚集键。这里可能需要解释清楚指针聚集键的区别,比如如果表有聚集索引,非聚集索引会使用聚集键作为指针,否则可能使用行ID。 性能方面,聚集索引在范围查询时效率高,因为数据物理连续,而非聚集索引可能需要回表,导致随机IO。但点查询的话,两者都可能很快,不过聚集索引直接找到数据,而非聚集索引需要二次查找。 维护成本方面,聚集索引的插入更新可能更耗时,因为要调整数据的位置,而非聚集索引只需要更新索引结构,不影响数据存储顺序。但如果有多个非聚集索引,更新数据时也需要维护这些索引,所以维护成本可能更高。 还需要提到每个表只能有一个聚集索引,而非聚集索引可以有多个。这也是重要的区别。 可能用户是数据库初学者,或者正在设计表结构,需要优化查询性能。他们可能想了解如何选择索引类型,或者为什么查询速度不同。所以例子会有帮助,比如用订单表,聚集索引在订单日期,这样按日期范围查询快;非聚集索引在客户ID,查询特定客户时需要回表查找。 需要确保语言简洁,结构清晰,分点说明。同时要避免专业术语过多,用容易理解的中文解释。可能还需要提醒使用场景,比如聚集索引适合经常需要范围查询的列,非聚集索引适合常用于查询条件的列,但更新频繁的表可能会有更多索引维护开销。 最后检查是否有错误,比如是否每个表真的只能有一个聚集索引,不同数据库是否有差异,但为了通用性,还是按常见情况说明。确保LaTeX格式正确,比如索引结构用行内公式表示,比如B+树结构。</think>聚集索引聚集索引是数据库索引的两种核心类型,主要区别体现在存储结构、数据组织方式查询效率上。以下是逐步对比分析: --- ### 一、定义对比 1. **聚集索引(Clustered Index)** $$ \text{索引键值的顺序 = 数据行的物理存储顺序} $$ 每个表**只能有一个**聚集索引,因为它直接决定了数据的物理排列。 2. **非聚集索引(Non-Clustered Index)** $$ \text{索引键值的顺序 ≠ 数据行的物理存储顺序} $$ 索引数据分离存储,一个表可创建**多个非聚集索引**。 --- ### 二、存储结构差异 | 特性 | 聚集索引 | 非聚集索引 | |---------------------|-----------------------------------|-----------------------------------| | **叶子节点内容** | 直接存储数据行 | 存储指向数据行的指针(或聚集索引键) | | **额外存储空间** | 不需要额外空间(索引即数据) | 需要独立存储空间(索引与数据分离) | | **逻辑示意图** | ![聚集索引结构] | ![非聚集索引结构] | --- ### 三、查询性能对比 1. **范围查询(如`WHERE date BETWEEN ...`)** - 聚集索引:数据物理连续,顺序读取快($O(\log n) + \text{顺序扫描}$)。 - 非聚集索引:需多次跳转,可能触发随机I/O($O(\log n) + \text{随机读取}$)。 2. **点查询(如`WHERE id = 5`)** - 两者效率接近(均通过B+树快速定位,$O(\log n)$),但非聚集索引需额外回表查数据。 --- ### 四、维护成本对比 1. **插入/更新数据** - 聚集索引:可能触发数据页分裂,影响性能。 - 非聚集索引:仅需更新索引结构,不影响数据物理顺序。 2. **删除数据** - 聚集索引:删除后可能导致页合并。 - 非聚集索引:只需标记索引条目为无效。 --- ### 五、适用场景 | 场景 | 推荐索引类型 | 原因 | |---------------------|-----------------------|------------------------------------| | 主键或频繁范围查询列 | 聚集索引 | 利用物理连续性加速范围查询 | | 高频筛选的非主键列 | 非聚集索引 | 快速定位数据,避免全表扫描 | | 频繁更新的列 | 谨慎创建非聚集索引 | 多个索引会增加写操作开销 | --- ### 六、示例说明 假设有一个订单表`Orders`: ```sql CREATE TABLE Orders ( OrderID INT PRIMARY KEY, -- 聚集索引(默认主键) CustomerID INT, OrderDate DATE, TotalAmount DECIMAL ); ``` - **场景1**:按`OrderDate`范围查询 ```sql SELECT * FROM Orders WHERE OrderDate BETWEEN '2023-01-01' AND '2023-12-31'; ``` 若在`OrderDate`上建聚集索引,数据按日期物理排序,查询更快。 - **场景2**:按`CustomerID`查找 ```sql SELECT * FROM Orders WHERE CustomerID = 1001; ``` 在`CustomerID`上建非聚集索引,通过索引快速定位,再回表获取完整数据。 --- ### 七、总结 | 维度 | 聚集索引 | 非聚集索引 | |-------------|----------------------------------|----------------------------------| | **物理存储** | 数据按索引排序存储 | 独立存储,数据无序 | | **数量限制** | 每表仅1个 | 每表可多个 | | **查询效率** | 范围查询快,避免回表 | 点查询快,但需回表 | | **适用列** | 主键、高频范围查询列 | 高频筛选的非主键列 |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值