探讨如何在有着 1000 万条数据的 MS SQL SERVER 数据库中实现快速的数据提取和数据分页。以下代码说明了我们实例中数据库的 “ 红头文件 ” 一表的部分数据结构:
CREATE TABLE [dbo].[TGongwen] ( --TGongwen 是红头文件表名
[Gid] [int] IDENTITY (1, 1) NOT NULL ,
-- 本表的 id 号,也是主键
[title] [varchar] (80) COLLATE Chinese_PRC_CI_AS NULL ,
-- 红头文件的标题
[fariqi] [datetime] NULL ,
-- 发布日期
[neibuYonghu] [varchar] (70) COLLATE Chinese_PRC_CI_AS NULL ,
-- 发布用户
[reader] [varchar] (900) COLLATE Chinese_PRC_CI_AS NULL ,
-- 需要浏览的用户。每个用户中间用分隔符 “,” 分开
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
下面,我们来往数据库中添加 1000 万条数据:
declare @i int
set @i=1
while @i<=250000
begin
insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-2-5',' 通信科 ',' 通信科 , 办公室 , 王局长 , 刘局长 , 张局长 ,admin, 刑侦支队 , 特勤支队 , 交巡警支队 , 经侦支队 , 户政科 , 治安支队 , 外事科 ',' 这是最先的 25 万条记录 ')
set @i=@i+1
end
GO
declare @i int
set @i=1
while @i<=250000
begin
insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-9-16',' 办公室 ',' 办公室 , 通信科 , 王局长 , 刘局长 , 张局长 ,admin, 刑侦支队 , 特勤支队 , 交巡警支队 , 经侦支队 , 户政科 , 外事科 ',' 这是中间的 25 万条记录 ')
set @i=@i+1
end
GO
declare @h int
set @h=1
while @h<=100
begin
declare @i int
set @i=2002
while @i<=2003
begin
declare @j int
set @j=0
while @j<50
begin
declare @k int
set @k=0
while @k<50
begin
insert into Tgongwen(fariqi,neibuyonghu,reader,title) values(cast(@i as varchar(4))+'-8-15 3:'+cast(@j as varchar(2))+':'+cast(@j as varchar(2)),' 通信科 ',' 办公室 , 通信科 , 王局长 , 刘局长 , 张局长 ,admin, 刑侦支队 , 特勤支队 , 交巡警支队 , 经侦支队 , 户政科 , 外事科 ',' 这是最后的 50 万条记录 ')
set @k=@k+1
end
set @j=@j+1
end
set @i=@i+1
end
set @h=@h+1
end
GO
declare @i int
set @i=1
while @i<=9000000
begin
insert into Tgongwen(fariqi,neibuyonghu,reader,title) values('2004-5-5',' 通信科 ',' 通信科 , 办公室 , 王局长 , 刘局长 , 张局长 ,admin, 刑侦支队 , 特勤支队 , 交巡警支队 , 经侦支队 , 户政科 , 治安支队 , 外事科 ',' 这是最后添加的 900 万条记录 ')
set @i=@i+1000000
end
GO
通过以上语句,我们创建了 25 万条由于 2004 年 2 月 5 日发布的记录, 25 万条由办公室于 2004 年 9 月 6 日发布的记录, 2002 年和 2003 年各 100 个 2500 条相同日期、不同分秒的记录(共 50 万条),还有由通信科于 2004 年 5 月 5 日发布的 900 万条记录,合计 1000 万条。
** 一、因情制宜,建立 ** ** “ ** ** 适当 ** ** ” ** ** 的索引 **
建立 “ 适当 ” 的索引是实现查询优化的首要前提。
索引( index )是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。当根据索引码的值搜索数据时,索引提供了对数据的快速访问。事实上,没有索引 , 数据库也能根据 SELECT 语句成功地检索到结果,但随着表变得越来越大,使用 “ 适当 ” 的索引的效果就越来越明显。注意,在这句话中,我们用了 “ 适当 ” 这个词,这是因为,如果使用索引时不认真考虑其实现过程,索引既可以提高也会破坏数据库的工作性能。
(一)深入浅出理解索引结构
实际上,您可以把索引理解为一种特殊的目录。微软的 SQL SERVER 提供了两种索引:聚集索引( clustered index ,也称聚类索引、簇集索引)和非聚集索引( nonclustered index ,也称非聚类索引、非簇集索引)。下面,我们举例来说明一下聚集索引和非聚集索引的区别:
其实,我们的汉语字典的正文本身就是一个聚集索引。比如,我们要查 “ 安 ” 字,就会很自然地翻开字典的前几页,因为 “ 安 ” 的拼音是 “an” ,而按照拼音排序汉字的字典是以英文字母 “a” 开头并以 “z” 结尾的,那么 “ 安 ” 字就自然地排在字典的前部。如果您翻完了所有以 “a” 开头的部分仍然找不到这个字,那么就说明您的字典中没有这个字;同样的,如果查 “ 张 ” 字,那您也会将您的字典翻到最后部分,因为 “ 张 ” 的拼音是 “zhang” 。也就是说,字典的正文部分本身就是一个目录,您不需要再去查其他目录来找到您需要找的内容。
我们把这种正文内容本身就是一种按照一定规则排列的目录称为 “ 聚集索引 ” 。
如果您认识某个字,您可以快速地从自动中查到这个字。但您也可能会遇到您不认识的字,不知道它的发音,这时候,您就不能按照刚才的方法找到您要查的字,而需要去根据 “ 偏旁部首 ” 查到您要找的字,然后根据这个字后的页码直接翻到某页来找到您要找的字。但您结合 “ 部首目录 ” 和 “ 检字表 ” 而查到的字的排序并不是真正的正文的排序方法,比如您查 “ 张 ” 字,我们可以看到在查部首之后的检字表中 “ 张 ” 的页码是 672 页,检字表中 “ 张 ” 的上面是 “ 驰 ” 字,但页码却是 63 页, “ 张 ” 的下面是 “ 弩 ” 字,页面是 390 页。很显然,这些字并不是真正的分别位于 “ 张 ” 字的上下方,现在您看到的连续的 “ 驰、张、弩 ” 三字实际上就是他们在非聚集索引中的排序,是字典正文中的字在非聚集索引中的映射。我们可以通过这种方式来找到您所需要的字,但它需要两个过程,先找到目录中的结果,然后再翻到您所需要的页码。
我们把这种目录纯粹是目录,正文纯粹是正文的排序方式称为 “ 非聚集索引 ” 。
通过以上例子,我们可以理解到什么是 “ 聚集索引 ” 和 “ 非聚集索引 ” 。
进一步引申一下,我们可以很容易的理解:每个表只能有一个聚集索引,因为目录只能按照一种方法进行排序。
(二)何时使用聚集索引或非聚集索引
下面的表总结了何时使用聚集索引或非聚集索引(很重要)。
动作描述
使用聚集索引
使用非聚集索引
列经常被分组排序
应
应
返回某范围内的数据
应
不应
一个或极少不同值
不应
不应
小数目的不同值
应
不应
大数目的不同值
不应
应
频繁更新的列
不应
应
外键列
应
应
主键列
应
<SPAN style="FONT-SIZE: 10.5pt; COLOR: #333333; LINE-H