网站导航网学 原创论文 原创专题 网站设计 最新系统 原创论文 论文降重 发表论文 论文发表 UI设计定制 论文答辩PPT格式排版 期刊发表 论文专题
返回网学首页
网学原创论文
最新论文 推荐专题 热门论文 论文专题
当前位置: 网学 > 设计资源 > 数据库 > 正文

千万数据的连续ID表,快速读取其中指定的某1000条数据?

论文降重修改服务、格式排版等 获取论文 论文降重及排版 论文发表 相关服务

有这样一个需求:一张上千万数据的表,结构很简单:ID是自增的,你怎么快速读取其中指定的某1000条数据,比如100万到100万零1000?

这个需求其实很简单,因为是自增型ID,可能分两种状况:有聚集索引或Heap,如果是后者,我想用ID和新增时间组建非聚集索引。效果应该相差不大。

于是动手,过程如下:

一、准备测试数据:

基本测试环境:

邀月工作室

插入1000万测试数据:

  1. /***************创建千万级测试数据库*********** 
  2. ****************downmoon 3w@live.cn ***************/ 
  3.  
  4. Create database HugeData_10Millons 
  5. go 
  6. use HugeData_10Millons 
  7. go 
  8.  
  9. /***************创建测试表********************* 
  10. ****************downmoo  3w@live.cn ***************/ 
  11.  
  12. IF NOT OBJECT_ID('[bigTable]'IS NULL 
  13.     DROP TABLE [bigTable] 
  14. GO 
  15. Create table bigTable 
  16. (PID int identity(1,1) primary key not null 
  17. ,PName nvarchar(100) null 
  18. ,AddTime dateTime null 
  19. ,PGuid Nvarchar(40) 
  20. go 
  21.  
  22. truncate table [bigTable] 
  23.  
  24. /***************创建第一个25万测试数据********************* 
  25. ****************downmoo  3w@live.cn ***************/ 
  26.  
  27. declare @d datetime  
  28. set @d=getdate()  
  29.  
  30. declare @i int 
  31. set @i=1 
  32. while @i<=250000 
  33. begin 
  34.     insert into [bigTable] 
  35.     select cast(datepart(ms,getdate()) as nvarchar(3))+Replicate('A',datepart(ss,getdate())) 
  36.     ,getdate() 
  37.     ,NewID() 
  38.     set @i=@i+1 
  39. end 
  40.  
  41. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  42.  
  43. /* 
  44. 语句执行花费时间(毫秒) 
  45. 94750 
  46. */ 
  47.  
  48. /***************创建第二个25万测试数据********************* 
  49. ****************downmoo  3w@live.cn ***************/ 
  50.  
  51. declare @d datetime  
  52. set @d=getdate()  
  53.  
  54. declare @i int 
  55. set @i=1 
  56. while @i<=250000 
  57. begin 
  58.     insert into [bigTable] 
  59.     select cast(datepart(ms,getdate()) as nvarchar(3))+Replicate(Substring(cast(NEWID() as nvarchar(40)),1,6),3) 
  60.     ,getdate() 
  61.     ,NewID() 
  62.     set @i=@i+1 
  63. end 
  64.  
  65. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  66.  
  67. /* 
  68. 语句执行花费时间(毫秒) 
  69. 115640 
  70. */ 
  71.  
  72. /***************创建900万测试数据********************* 
  73. ****************downmoo  3w@live.cn ***************/ 
  74.  
  75. declare @d datetime  
  76. set @d=getdate()  
  77.  
  78. declare @i int 
  79. set @i=1 
  80. while @i<=9000000 
  81. begin 
  82.     insert into [bigTable] 
  83.     select replicate('X',ROUND((RAND()* 60),0) )+cast(datepart(ms,getdate()) as nvarchar(3)) 
  84.     ,getdate() 
  85.     ,NewID() 
  86.     set @i=@i+1 
  87. end 
  88.  
  89. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  90. /* 
  91. 语句执行花费时间(毫秒) 
  92. 3813686 
  93. */ 
  94.  
  95. /***************创建最后50万测试数据********************* 
  96. ****************downmoo  3w@live.cn ***************/ 
  97.  
  98. declare @d datetime  
  99. set @d=getdate()  
  100.  
  101. declare @i int 
  102. set @i=1 
  103. while @i<=500000 
  104. begin 
  105.     insert into [bigTable] 
  106.     select replicate('X',ROUND((RAND()* 60),0) )+cast(NewID() as nvarchar(40)) 
  107.     ,getdate() 
  108.     ,NewID() 
  109.     set @i=@i+1 
  110. end 
  111.  
  112. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  
  113. /* 
  114. 语句执行花费时间(毫秒) 
  115. 207436 
  116. */ 
  117.  
  118. /* 
  119. 检查数量 
  120. select count(1) from dbo.bigTable 
  121. ----------10000000 
  122. 清除日志 
  123. DUMP TRANSACTION HugeData_10Millons WITH NO_LOG 
  124. BACKUP LOG HugeData_10Millons WITH NO_LOG 
  125. DBCC SHRINKDATABASE(HugeData_10Millons) 
  126.  
  127. */ 

完成后,数据文件大小如下:

 

邀月工作室

二、创建一个存储过程用于测试:

  1. /***************查中间某段1000条顺序数据********************* 
  2. ****************downmoo  3w@live.cn ***************/ 
  3. Create procedure GetTop1000RecordsByRange 
  4. (@begin int 
  5. ,@end int 
  6. as  
  7. select top 1000 * from [bigTable] 
  8. where PID between @begin and @end 
  9. go 

邀月说明:其实,加不加top对查询并没有影响。后面的测试证实了这一点。因为将top 1000 去掉后,清除过程计划缓存,仍然得出相同的计划结果。
测试语句:

  1. declare @d datetime  
  2. set @d=getdate()  
  3.  
  4. exec GetTop100RecordsByRange 1000000,10001000 
  5.  
  6. select [语句执行花费时间(毫秒)]=datediff(ms,@d,getdate())  

 

此时,由于SQL Server默认为主键PID创建了聚集索引,查询速度比较理想,平均为0-16毫秒之间,更接近于0

查询计划也如我所料:邀月工作室

 而如果以Pguid作为聚集索引键,查询计划如下:

邀月工作室

如果以AddTime作为聚集索引键,查询计划:

邀月工作室

 三、修改聚集索引,以检查查询速度

  1. /*删除系统自动创建的聚集索引 
  2. */ 
  3. ALTER TABLE [dbo].[bigTable] DROP CONSTRAINT [PK__bigTable__7C8480AE] 
  4. go 
  5.  
  6.  
  7. /*创建一个非聚集索引 
  8. 在PID和addtime字段 
  9. */ 
  10. CREATE NONCLUSTERED INDEX bigTable_NoClusIdx 
  11. ON [bigTable]([AddTime] ASC,[PID] ASC); 
  12. go 
  13. DROP Index [bigTable_NoClusIdx] on dbo.[bigTable] 
  14.  
  15.  
  16. /*创建一个非聚集索引 
  17. 在PID字段 
  18. */ 
  19.  
  20. Create NONCLUSTERED INDEX bigTable_NoclusIdx 
  21. ON [bigTable](PID); 
  22. go 
  23.  
  24. DROP Index [bigTable_NoClusIdx] on dbo.[bigTable] 
  25.  
  26. /*创建一个非聚集索引 
  27. 在AddTime字段 
  28. */ 
  29. CREATE NONCLUSTERED INDEX bigTable_NoclusIdx 
  30. ON [bigTable](AddTime); 
  31. go 
  32.  
  33. DROP Index [bigTable_NoClusIdx] on dbo.[bigTable] 
  34.  
  35. /*创建一个非聚集索引 
  36. 在GUID字段 
  37. */ 
  38.  
  39. CREATE NONCLUSTERED INDEX bigTable_NoclusIdx 
  40. ON [bigTable](PGuid); 
  41. go 
  42.  
  43. DROP Index [bigTable_NoClusIdx] on dbo.[bigTable] 
  44.  
  45.  
  46. /*创建一个聚集索引 
  47. 在GUID字段 
  48. */ 
  49.  
  50. CREATE CLUSTERED INDEX bigTable_ClusIdx 
  51. ON [bigTable](PGuid); 
  52. go 
  53.  
  54. DROP Index [bigTable_ClusIdx] on dbo.[bigTable] 
  55.  
  56. /*创建一个聚集索引 
  57. 在addTime字段 
  58. */ 
  59. CREATE CLUSTERED INDEX bigTable_ClusIdx 
  60. ON [bigTable](AddTime); 
  61. go 
  62.  
  63. DROP Index [bigTable_ClusIdx] on dbo.[bigTable] 
  64.  
  65.  
  66. /*创建一个聚集索引 
  67. 在PID字段 
  68. */ 
  69. CREATE CLUSTERED INDEX bigTable_ClusIdx 
  70. ON [bigTable](PID); 
  71. go 

测试结果有些令我意外:
1、在没有聚集索引的前提下,无论在GUID,AddTime,PID创建非聚集索引,查询的速度均相差甚远。平均在200毫秒以上,并且此时每次查询均在10秒以上。这与查询的计划缓存有关。
2、在创建聚集索引时,性能PID>AddTime>PGuid,但总体相差不明显。
四、检查索引存储内部
使用微软未公开的一个命令DBCC IND

  1. DBCC IND (HugeData_10Millons, bigTable, -1); 

结果约有21万个数据页:(211985 row(s) affected)

为了更方便找出根页(Root Page),我们使用一个表来存放DBCC IND的查询结果:

  1. IF OBJECTPROPERTY(object_id('sp_tablepages'), 'IsUserTable'IS NOT NULL 
  2.     DROP TABLE sp_tablepages; 
  3. go 
  4.  
  5. CREATE TABLE sp_tablepages 
  6.     PageFID         tinyint, 
  7.     PagePID         int
  8.     IAMFID          tinyint, 
  9.     IAMPID          int
  10.     ObjectID        int
  11.     IndexID         tinyint, 
  12.     PartitionNumber tinyint, 
  13.     PartitionID     bigint
  14.     iam_chain_type  varchar(30), 
  15.     PageType        tinyint, 
  16.     IndexLevel      tinyint, 
  17.     NextPageFID     tinyint, 
  18.     NextPagePID     int
  19.     PrevPageFID     tinyint, 
  20.     PrevPagePID     int
  21.     CONSTRAINT sp_tablepages_PK 
  22.         PRIMARY KEY (PageFID, PagePID) 
  23. ); 
  24. go 
  25. --TRUNCATE TABLE sp_tablepages; 
  26. INSERT sp_tablepages 
  27. EXEC ('DBCC IND (HugeData_10Millons, bigTable, 1)'); 
  28. go 
  29.  
  30. SELECT IndexLevel 
  31.     , PageFID 
  32.     , PagePID 
  33.     , PrevPageFID 
  34.     , PrevPagePID 
  35.     , NextPageFID 
  36.     , NextPagePID 
  37. FROM sp_tablepages 
  38. ORDER BY IndexLevel DESC, PrevPagePID; 
  39. GO  

假定我们要找PID为100000的记录。附查找过程如下:

邀月工作室

/uploadfile/201101/14/1614228510.png?psid=1

邀月工作室

邀月工作室

小结:
1、一个聚集索引的叶级正好就是数据自身,所以当一个聚集索引被创建时,表中数据被复制并依据聚集键排序,聚集索引被逻辑维护而不是物理维护。这样,查询时通过逻辑扫描可以很快找到某行所在的索引页,进而找出连续的1000条记录所在的页。
2、对于一个非聚集索引来说,如果是Heap,行的标识就是它们的物理行标识(RID);如果是聚集表,则为聚集健,这个值称为书签值(bookmaark value),它和索引键、包含性列一起组成了非聚集索引的叶级。另外,在B树查找非叶级的页时,将可能不得不通过指向子页的指针进行物理定位,这可能会增加查询的时间。还有,非聚集索引仅仅包含被索引定义的数据,对于没有在索引中定义的数据,可能需要在物理行进行一个书签查找(bookmark lookup)。
3、对于大数据量的查询,建立聚集索引是必须的。如果查询以ID序列为主,可以直接在标识列建立聚集索引。如果查询以时间段为主,则可以考虑用时间和标识列建聚集索引。
以上结论谨供参考,欢迎交流。

  • 下一篇资讯: EXISTS、IN与JOIN性能分析
  • 设为首页 | 加入收藏 | 网学首页 | 原创论文 | 计算机原创
    版权所有 网学网 [Myeducs.cn] 您电脑的分辨率是 像素
    Copyright 2008-2020 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号 常年法律顾问:王律师