为什麽我们一般会在自增列或交易时间列上建立聚集索引?

http://www.cnblogs.com/lyhabc/p/3533027.html

一般的交易系统里面我们都会以自增列或交易时间列作为聚集索引列,因为一般这些系统都是写多读少

每天的交易数据会不停的插入到数据库,但是读取数据就没有数据插入那么频繁

因为这些系统一般是写多读少,所以我们会选择在自增列或交易时间列上建立聚集索引



测试

测试环境:SQLSERVER2012 SP1  WINDOWS7 64位

我们来做一个测试,测试脚本如下:

 1 --测试脚本  插入性能
 2 USE [test]
 3 GO
 4 --建表 以transtime为聚集索引列
 5 CREATE TABLE transtable(tranid INT ,transtime DATETIME)
 6 GO
 7 CREATE CLUSTERED INDEX CIX_transtable ON [dbo].[transtable]([transtime])
 8 GO
 9
10 --建表 以tranid为聚集索引列
11 CREATE TABLE transtable2(tranid INT ,transtime DATETIME)
12 GO
13 CREATE CLUSTERED INDEX CIX_transtable2 ON [dbo].[transtable2]([tranid])
14 GO
15
16
17 ----------------------------------------------------------
18 --先插入测试数据,插入的tranid都为基数
19 DECLARE @i INT
20 SET @i = 1
21 WHILE @i <= 1000000
22     BEGIN
23         INSERT  INTO [dbo].[transtable]
24                 SELECT  @i , GETDATE()
25         SET @i = @i + 2
26     END
27 --------------------------------------
28 DECLARE @i INT
29 SET @i = 1
30 WHILE @i <= 1000000
31     BEGIN
32         INSERT  INTO [dbo].[transtable2]
33                 SELECT  @i , GETDATE()
34         SET @i = @i + 2
35     END
36
37 -------------------------------------------

在transtable表上的transtime(交易时间)上建立聚集索引,在transtable2表上的tranid(交易编号)上建立聚集索引

我们分别在两个表上插入500000条记录,插入的时候有个特点,就是插入的tranid都是基数

1 SELECT COUNT(*) FROM [dbo].[transtable]
2 SELECT COUNT(*) FROM [dbo].[transtable2]
3
4 SELECT TOP 10 * FROM [dbo].[transtable] ORDER BY [tranid]
5 SELECT TOP 10 * FROM [dbo].[transtable2] ORDER BY [tranid] 

我们创建两个存储过程,这两个存储过程为插入到表数据

 1 --------------------------------------------
 2 --创建两个存储过程
 3 CREATE PROC INSERTTranstable
 4 AS
 5     DECLARE @i INT
 6     SET @i = 1
 7     WHILE @i <= 1000
 8         BEGIN
 9             IF ( @i % 2 = 0 )
10                 BEGIN
11                     INSERT  INTO [dbo].[transtable]
12                             SELECT  @i ,
13                                     GETDATE()
14                     SET @i = @i + 1
15                 END
16             ELSE
17                 BEGIN
18                     SET @i = @i + 1
19                     CONTINUE
20                 END
21         END
22 ------------------------------------------
23 CREATE PROC INSERTTranstable2
24 AS
25     DECLARE @i INT
26 SET @i = 1
27 WHILE @i <= 1000
28     BEGIN
29         IF ( @i % 2 = 0 )
30             BEGIN
31                 INSERT  INTO [dbo].[transtable2]
32                         SELECT  @i ,
33                                 GETDATE()
34                 SET @i = @i + 1
35             END
36         ELSE
37             BEGIN
38              SET @i = @i + 1
39                 CONTINUE
40             END
41     END
42 ----------------------------
 1 --------------------------------------------
 2 --创建两个存储过程
 3 CREATE PROC INSERTTranstable
 4 AS
 5     DECLARE @i INT
 6     SET @i = 1
 7     WHILE @i <= 1000
 8         BEGIN
 9             IF ( @i % 2 = 0 )
10                 BEGIN
11                     INSERT  INTO [dbo].[transtable]
12                             SELECT  @i ,
13                                     GETDATE()
14                     SET @i = @i + 1
15                 END
16             ELSE
17                 BEGIN
18                     SET @i = @i + 1
19                     CONTINUE
20                 END
21         END
22 ------------------------------------------
23 CREATE PROC INSERTTranstable2
24 AS
25     DECLARE @i INT
26 SET @i = 1
27 WHILE @i <= 1000
28     BEGIN
29         IF ( @i % 2 = 0 )
30             BEGIN
31                 INSERT  INTO [dbo].[transtable2]
32                         SELECT  @i ,
33                                 GETDATE()
34                 SET @i = @i + 1
35             END
36         ELSE
37             BEGIN
38              SET @i = @i + 1
39                 CONTINUE
40             END
41     END
42 -----------------------------

测试脚本,测试一下插入到两个表的时间

 1 测试插入偶数行的性能
 2 DECLARE @a DATETIME
 3 DECLARE @b DATETIME
 4 SELECT @a=GETDATE()
 5 EXEC INSERTTranstable
 6 SELECT @b=GETDATE()
 7 SELECT @[email protected]
 8 --------------------------------------
 9
10 DECLARE @c DATETIME
11 DECLARE @d DATETIME
12 SELECT @c=GETDATE()
13 EXEC INSERTTranstable2
14 SELECT @d=GETDATE()
15 SELECT @[email protected]
 1 测试插入偶数行的性能
 2 DECLARE @a DATETIME
 3 DECLARE @b DATETIME
 4 SELECT @a=GETDATE()
 5 EXEC INSERTTranstable
 6 SELECT @b=GETDATE()
 7 SELECT @[email protected]
 8 --------------------------------------
 9
10 DECLARE @c DATETIME
11 DECLARE @d DATETIME
12 SELECT @c=GETDATE()
13 EXEC INSERTTranstable2
14 SELECT @d=GETDATE()
15 SELECT @[email protected]
 1 测试插入偶数行的性能
 2 DECLARE @a DATETIME
 3 DECLARE @b DATETIME
 4 SELECT @a=GETDATE()
 5 EXEC INSERTTranstable
 6 SELECT @b=GETDATE()
 7 SELECT @[email protected]
 8 --------------------------------------
 9
10 DECLARE @c DATETIME
11 DECLARE @d DATETIME
12 SELECT @c=GETDATE()
13 EXEC INSERTTranstable2
14 SELECT @d=GETDATE()
15 SELECT @[email protected]

验证一下偶数的交易编号是否已经插入到两个表中

1 SELECT TOP 10 * FROM [dbo].[transtable] ORDER BY [tranid]
2 SELECT TOP 10 * FROM [dbo].[transtable2] ORDER BY [tranid] 
1 SELECT TOP 10 * FROM [dbo].[transtable] ORDER BY [tranid]
2 SELECT TOP 10 * FROM [dbo].[transtable2] ORDER BY [tranid] 

我们看一下时间

第一个表

第二个表

很明显,第一个表比第二个表快,因为的机器的硬盘是固态硬盘,时间差距不是很大,如果是机械硬盘时间差距会大一些,那么究竟为什麽会造成这种情况呢?

我们用下图来解析一下

我们先说第二张表

当交易编号为2的那条记录插入进来的时候,后面的记录都需要向后移动,以使交易编号从小到大排序,因为聚集索引建立在交易编号列上

这个移动时间是有开销的,而且每次偶数交易编号插入到表中,每插入一次就移动一次,而当前面的记录插入到表中的时候移动的记录数就越多

例如:tranid:2,transtime:2014-1-26 31:22.180插入到表中的时候后面的记录都需要移动,而tranid:978,transtime:2014-01-26 00:29:10.830

这条记录插入到表中的时候,后面需要移动的记录数就没有那么多,总之那个开销挺大的。。。

第一张表的情况

因为第一张表是以交易时间为聚集索引列的,所以无论交易编号是多少,记录都会插入到表的最后,因为后来的记录的交易时间肯定比前面的记录的交易时间大

这样的话,基本上没有开销



现实系统中的情况

实际系统中,新生成的要插入到表中的交易编号是有可能小于当前表中的某条记录的交易编号的,那么这时候记录插入到表中就需要移位(如果聚集索引建立在交易编号上)

如果聚集索引建立在交易时间上,那么新生成的要插入到表中的交易记录时间肯定会大于当前表中的任何一条交易记录的时间

(除非人为修改系统时间造成当前时间比数据库中的某些记录的交易时间要早)



总结

前公司的数据库有些表在自增列,有些表在交易时间列上建立了聚集索引,在交易时间列上建立聚集索引个人觉得很正常

因为在查询的时候按照交易时间来排序《order by 交易时间》,速度上是很快的,但是除了排序之外还有一个作用就是本文所讲到的

插入数据到表中的效率问题

个人觉得一般商场管理系统,油站管理系统都是这类型系统

本文的意见纯属我自己的个人意见,并不一定适合您的系统,如果交易时间的选择性不是太高的话,那么可能在交易时间或自增列上建立聚集索引就不是太合适了

我们以前的系统的交易时间的选择性是挺高的,而且通常查询都需要按照交易时间排序,那么聚集索引列建立在交易时间上就是比较好了

本次实验用到的完整脚本

1 --测试脚本  插入性能
  2 USE [test]
  3 GO
  4 --建表 以transtime为聚集索引列
  5 CREATE TABLE transtable(tranid INT ,transtime DATETIME)
  6 GO
  7 CREATE CLUSTERED INDEX CIX_transtable ON [dbo].[transtable]([transtime])
  8 GO
  9
 10 --建表 以tranid为聚集索引列
 11 CREATE TABLE transtable2(tranid INT ,transtime DATETIME)
 12 GO
 13 CREATE CLUSTERED INDEX CIX_transtable2 ON [dbo].[transtable2]([tranid])
 14 GO
 15
 16 ----------------------------------------------------------
 17 --先插入测试数据,插入的tranid都为基数
 18 DECLARE @i INT
 19 SET @i = 1
 20 WHILE @i <= 1000000
 21     BEGIN
 22         INSERT  INTO [dbo].[transtable]
 23                 SELECT  @i , GETDATE()
 24         SET @i = @i + 2
 25     END
 26 --------------------------------------
 27 DECLARE @i INT
 28 SET @i = 1
 29 WHILE @i <= 1000000
 30     BEGIN
 31         INSERT  INTO [dbo].[transtable2]
 32                 SELECT  @i , GETDATE()
 33         SET @i = @i + 2
 34     END
 35
 36 -------------------------------------------
 37 SELECT COUNT(*) FROM [dbo].[transtable]
 38 SELECT COUNT(*) FROM [dbo].[transtable2]
 39
 40 SELECT TOP 10 * FROM [dbo].[transtable] ORDER BY [tranid]
 41 SELECT TOP 10 * FROM [dbo].[transtable2] ORDER BY [tranid]
 42
 43 --------------------------------------------
 44 --创建两个存储过程
 45 CREATE PROC INSERTTranstable
 46 AS
 47     DECLARE @i INT
 48     SET @i = 1
 49     WHILE @i <= 1000
 50         BEGIN
 51             IF ( @i % 2 = 0 )
 52                 BEGIN
 53                     INSERT  INTO [dbo].[transtable]
 54                             SELECT  @i ,
 55                                     GETDATE()
 56                     SET @i = @i + 1
 57                 END
 58             ELSE
 59                 BEGIN
 60                     SET @i = @i + 1
 61                     CONTINUE
 62                 END
 63         END
 64 ------------------------------------------
 65 CREATE PROC INSERTTranstable2
 66 AS
 67     DECLARE @i INT
 68 SET @i = 1
 69 WHILE @i <= 1000
 70     BEGIN
 71         IF ( @i % 2 = 0 )
 72             BEGIN
 73                 INSERT  INTO [dbo].[transtable2]
 74                         SELECT  @i ,
 75                                 GETDATE()
 76                 SET @i = @i + 1
 77             END
 78         ELSE
 79             BEGIN
 80              SET @i = @i + 1
 81                 CONTINUE
 82             END
 83     END
 84 -----------------------------
 85
 86 测试插入偶数行的性能
 87 DECLARE @a DATETIME
 88 DECLARE @b DATETIME
 89 SELECT @a=GETDATE()
 90 EXEC INSERTTranstable
 91 SELECT @b=GETDATE()
 92 SELECT @[email protected]
 93 --------------------------------------
 94
 95 DECLARE @c DATETIME
 96 DECLARE @d DATETIME
 97 SELECT @c=GETDATE()
 98 EXEC INSERTTranstable2
 99 SELECT @d=GETDATE()
100 SELECT @[email protected]
时间: 2024-09-29 12:30:13

为什麽我们一般会在自增列或交易时间列上建立聚集索引?的相关文章

Oracle在表上建立自增字段的方法

本方法为使用SEQUENCE(序列) 例如有表temp_test结构为: create table TEMP_TEST ( id number, nm varchar(10), primary key(id)   //id为主键,下面的方法把它设为自增字段) 1.建立自增序列TEMP_TEST_IDADD,命名任意,从1开始,每次加1 CREATE SEQUENCE TEMP_TEST_IDADD INCREMENT BY 1 START WITH 1; 2.在表temp_test上建立触发器如

夺命雷公狗---Thinkphp----12之文章的增删改查(图片上传和关联查询)

我们由于表分析的不够完善,所以我们来加多一个tid的字段,到时候主要目的是为了更好的遍历出文章是属于那个分类下的,表如下所示: 那么下一步我们就开始创建一个ArticleController.class.php的控制器,用来管理文章的增删改查操作,所以我们开始第一步来实现文章的添加,我们先来实现他的增加功能: public function add(){ if(IS_POST){ $data['title'] = I('title'); $data['tid'] = I('tid'); $dat

beego框架配合easyui实现增删改查及图片上传

demo目录: upload文件夹主要放置上传的头像文件,main是主文件,所有效果如下: 主页面: 具体代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>基于golang的后台管理系统</title> <link rel="stylesheet" type="t

三级菜单的增删改-2018.2.22(上)

1.首先把字典内容存到txt文档里面 2.读取txt文本内容以及用eval将文本转化为字典 3.可以看出来昨天写的三级菜单并不适用今天要使用的增删改 #_author_:"Bushii" #data:2018/2/21 menu= { '山东' : { '青岛' : ['四方','黄岛','崂山','李沧','城阳'], '济南' : ['历城','槐荫','高新','长青','章丘'], '烟台' : ['龙口','莱山','牟平','蓬莱','招远'] }, '江苏' : { '苏

sql server 怎么为一个已经存在数据的table, 添加一个自增的主键列?

情况描述 如果你符合下面的情况, 可以参考本文的解决方案 你已经有了一个DB, 并且DB中也有了不少table, 但是table最开始的时候没有设置主键. 数据存入了一部分后, 突然想到为这个table添加主键并且自增的column. 并且不想丢失这部分数据时,,, 你的db是自己建的, 但是table以及table中的数据是通过其他的db export->import过来的, 此时新的db中的import进来的table可能是没有主键的, 即使import过来的列中包含id这种列,,, 网间对

转载:SqlServer数据库性能优化详解

本文转载自:http://blog.csdn.net/andylaudotnet/article/details/1763573 性能调节的目的是通过将网络流通.磁盘 I/O 和 CPU 时间减到最小,使每个查询的响应时间最短并最大限度地提高整个数据库服务器的吞吐量.为达到此目的,需要了解应用程序的需求和数据的逻辑和物理结构,并在相互冲突的数据库使用之间(如联机事务处理 (OLTP) 与决策支持)权衡. 对性能问题的考虑应贯穿于开发阶段的全过程,不应只在最后实现系统时才考虑性能问题.许多使性能得

Mysql千万级大表优化

Mysql的单张表的最大数据存储量尚没有定论,一般情况下mysql单表记录超过千万以后性能会变得很差.因此,总结一些相关的Mysql千万级大表的优化策略. 1.优化sql以及索引 1.1优化sql 1.有索引但未被用到的情况(不建议) (1)避免like的参数以通配符开头时 尽量避免Like的参数以通配符开头,否则数据库引擎会放弃使用索引而进行全表扫描. 以通配符开头的sql语句,例如:select * from t_credit_detail where Flistid like '%0'\G

SqlServer索引及优化详解

(一)深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clustered index,也称聚类索引.簇集索引)和非聚集索引(nonclustered index,也称非聚类索引.非簇集索引).下面,我们举例来说明一下聚集索引和非聚集索引的区别: 其实,我们的汉语字典的正文本身就是一个聚集索引.比如,我们要查“安”字,就会很自然地翻开字典的前几页,因为“安”的拼音是“an”,而按照拼音排序汉字的字典是以英文字母“a”开头并以“z”

mysql大数据高并发处理(转)

一.数据库结构的设计 如果不能设计一个合理的数据库模型,不仅会增加客户端和服务器段程序的编程和维护的难度,而且将会影响系统实际运行的性能.所以,在一个系统开始实施之前,完备的数据库模型的设计是必须的. 在一个系统分析.设计阶段,因为数据量较小,负荷较低.我们往往只注意到功能的实现,而很难注意到性能的薄弱之处,等到系统投入实际运行一段时间后,才发现系统的性能在降低,这时再来考虑提高系统性能则要花费更多的人力物力,而整个系统也不可避免的形成了一个打补丁工程. 所以在考虑整个系统的流程的时候,我们必须