现在的位置: 首页 > 综合 > 正文

SQL2005 表分区

2013年04月25日 ⁄ 综合 ⁄ 共 4303字 ⁄ 字号 评论关闭

我用sqlserver2005的分区表功能,建了一个大数据量的分区表,
过程如下:
建文件组
ALTER DATABASE [aqs2211] ADD FILEGROUP [fg2008]
ALTER DATABASE [aqs2211] ADD FILEGROUP [fg2009]
ALTER DATABASE [aqs2211] ADD FILEGROUP [fg2010]
ALTER DATABASE [aqs2211] ADD FILEGROUP [fg2011]
ALTER DATABASE [aqs2211] ADD FILEGROUP [fg2012]

ALTER DATABASE [aqs2211] ADD FILE
(NAME = N'aqs2211_Data2008',
FILENAME = N'G:\xp\data\aqs2211_Data2008.ndf',
SIZE = 2048KB , FILEGROWTH = 1024KB ) TO FILEGROUP [fg2008]

ALTER DATABASE [aqs2211] ADD FILE
(NAME = N'aqs2211_Data2009',
FILENAME = N'G:\xp\data\aqs2211_Data2009.ndf',
SIZE = 2048KB , FILEGROWTH = 1024KB ) TO FILEGROUP [fg2009]

ALTER DATABASE [aqs2211] ADD FILE
(NAME = N'aqs2211_Data2010',
FILENAME = N'G:\xp\data\aqs2211_Data2010.ndf',
SIZE = 2048KB , FILEGROWTH = 1024KB ) TO FILEGROUP [fg2010]

ALTER DATABASE [aqs2211] ADD FILE
(NAME = N'aqs2211_Data2011',
FILENAME = N'G:\xp\data\aqs2211_Data2011.ndf',
SIZE = 2048KB , FILEGROWTH = 1024KB ) TO FILEGROUP [fg2011]

ALTER DATABASE [aqs2211] ADD FILE
(NAME = N'aqs2211_Data2012',
FILENAME = N'G:\xp\data\aqs2211_Data2012.ndf',
SIZE = 2048KB , FILEGROWTH = 1024KB ) TO FILEGROUP [fg2012]

建分区函数:
CREATE PARTITION FUNCTION auditinfotb_pf ( datetime )
AS RANGE right
FOR VALUES ('2008-01-01','2009-01-01','2010-01-01','2011-01-01')

建分区架构:
CREATE PARTITION FUNCTION auditinfotb_pf ( datetime )
AS RANGE right
FOR VALUES ('2008-01-01','2009-01-01','2010-01-01','2011-01-01')

建分区表
CREATE TABLE auditinfotb (
id char(20) NOT NULL ,
localCode varchar(6) ,
appCode char(5) NOT NULL ,
userIP varchar(15) DEFAULT NULL ,
userRoleCode varchar(80) DEFAULT NULL ,
privilegeCode varchar(512) DEFAULT NULL ,
succeed char(1) DEFAULT NULL ,
errMsg varchar(256) DEFAULT NULL ,
isLocalUser char(1) DEFAULT NULL ,
accessTime datetime NOT NULL ,
userName varchar(128) NOT NULL ,
userIDN varchar(32) DEFAULT NULL ,
orgCode char(12) DEFAULT NULL ,
policeType char(2) DEFAULT NULL ,
dutyLevel char(4) DEFAULT NULL ,
station char(4) DEFAULT NULL ,
charge char(4) DEFAULT NULL ,
ministry char(3) DEFAULT NULL ,
certRole char(6) DEFAULT NULL ,
orgName varchar(256) DEFAULT NULL ,
appName varchar(256) DEFAULT NULL ,
appType char(4) DEFAULT NULL,
provCode char(2) DEFAULT NULL ,
cityCode char(2) DEFAULT NULL ,
countyCode char(2) DEFAULT NULL ,
unit1Code char(2) DEFAULT NULL ,
unit2Code char(2) DEFAULT NULL,
unit3Code char(2) DEFAULT NULL ,
) ON auditinfotbPS(accesstime)
;

分区表建好后我用导入导出工具,把数据导入进来
然后创建索引
create index INDEX_auditinfo_orgcode on auditinfotb (accesstime,orgcode);

索引建好后,我查询某日的记录的时候
比如:
select *from auditinfotb
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
就会全表扫描,
而另一个时间段比如
select *from auditinfotb
where accesstime>'2009-09-06'
and accesstime<'2009-09-07' 就会利用上索引,
这是怎么回事呢?

索引建好后,我查询某日的记录的时候
比如:
select *from auditinfotb
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
就会全表扫描,
而另一个时间段比如
select *from auditinfotb
where accesstime>'2009-09-06'
and accesstime<'2009-09-07' 就会利用上索引,

要不要用索引会根据你的数据统计信息,

假如你的表里面数据1000条,
'2009-06-01'的数据才1条两条

'2009-09-06'是表里面有几百条,

第一个肯定会用索引查找,再有序局部扫描加书签
第二个不在选择点上,则选择表扫描会更快,书签查找是比较耗费I/O的

补充:
比如
select * from auditinfotb2
where accesstime>'2009-05-01'
and accesstime<'2009-05-02'
能利用索引
这部分数据是44051条
而select * from auditinfotb2
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
就需要全部扫描,这部分数据是134716
这些数据相对于整个分区表8千多万数据来说,某一天的还是很少的,没道理利用不上索引的,而且
select count(*) from auditinfotb2
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'的话,也能利用上索引,这又是怎么回事呢?

分区表建好后我用导入导出工具,把数据导入进来
然后创建索引
create index INDEX_auditinfo_orgcode on auditinfotb (accesstime,orgcode)
ON auditinfotbPS(accesstime)

你的表没有聚集索引,应该

create CLUSTERED index INDEX_auditinfo_orgcode on auditinfotb (accesstime,orgcode)
ON auditinfotbPS(accesstime)

而select * from auditinfotb2
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
就需要全部扫描,这部分数据是134716
这些数据相对于整个分区表8千多万数据来说,某一天的还是很少的,没道理利用不上索引的,而且
select count(*) from auditinfotb2
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'的话,也能利用上索引,这又是怎么回事呢?

没道理利用不上索引???那你觉得为什么要用得上索引呢,??有时候是会估算失败,你可以尝试指定你的索引执行看一下效率.

select count(*) from auditinfotb2
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'的话,也能利用上索引,这又是怎么回事呢?
这是COUNT(*) 不是*,
*号是所有数据,页COUNT(*)只是一个标量聚合,只取行数就行了,不用把数据给弄出来

6/1=13471笔,如果使用索引seek,那么意味着至少有13471个随机IO(忽略索引层级不谈).

通常随机IO的代价要远远高于顺序IO,因为数据分布的问题,随机IO需要移动更多次的磁臂才能读取到数据,而
顺序IO可以使用预读等机制提供更快的读取速度。

回到你的问题,在未分区前,8000W的数据做scan可代价要高于13471次随机IO,故会使用seek.

但分区后,变成只需要扫描一个表分区即可,所以,优化器会更倾向于选择分区表扫描。

再看你提的
select top 20 * From auditinfotb
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
------------耗时32秒
select top 20 * From auditinfotb with (index=index_auditinfo_orgcode)
where accesstime>'2009-06-01'
and accesstime<'2009-06-02'
------------- 耗时0秒

第2个查询耗时0秒的原因是,SQLSERVER只使用了20次索引查找,所以耗时很短。这样没有什么可比性。

要了解优化器为什么没有采用索引查找,请打开IO/CPU读数,把TOP 20 去掉,然后再比较看看。

抱歉!评论已关闭.