SQLServer相关

本文详细介绍了数据库索引的基础概念,包括二叉平衡树、B树、B+树等数据结构,以及聚集索引与非聚集索引的原理与实现。重点探讨了索引在数据库中的作用、优化策略及其与约束的区别,并通过SQL代码实例展示了如何创建和查询索引结构。文章还涉及了堆表索引结构和解析RID的方法,旨在帮助读者深入理解数据库索引的底层逻辑与实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 最近在学习数据库索引,所以在这里记录下最近的学习心得。

 

   热身学习。

     1.二叉平衡树和B树B+树的概念需要了解。

     2.了解二叉平衡树的旋转。

     3.思考为何数据库索引不使用二叉平衡树而选择B树或者B+树。

     4.思考B+树作为索引相对于B树的优点在哪里。

      

        具体可以参考:

                 MySQL索引背后的数据结构及算法原理

                 平衡二叉树_B树严蔚敏老师

 

   知识总结

      1.聚集索引

 

         叶子节点包含聚集键值和全部数据。

 

         表中的数据顺序通过聚集键的顺序来维护,聚集索引树本身就包含了一个表。

                单独的外链双链表来进行页之间的维护。也就是说在每页中是有序的,每个页也是有序的。

 

        思考,那如果页的最后一条数据添加或者删除会有哪些情况?

 

        思考,聚集键值唯一性,宽度,易变性因素对整个索引产生的影响。

                  唯一性在下面的问题中探讨。

                  宽度的影响首先影响本身B树的每个节点的度,其次辅助索叶子节点引用键值的成本增加。

                 易变性使其记录需要重新定位,容易产生页面分离和碎片。其次每个辅助索引需要修改。

 

        思考,通过聚集键找到叶子节点的时候,将叶子节点的页面加载进来的时候是通过二分查找吗?

 

 

  

 

 

     2.非聚集索引

 

       叶子节点存储的是索引键值和【聚集键或者sqlserver生成物理标示符RID】

 

       思考RID是sqlserver自动生成的,还是真实物理地址。?

              真实的物理行号。

 

       思考,为何聚集键值必须唯一。

              假设聚集键值不唯一,聚集键为姓名,非聚集键值为身份证号,如果一个非聚集索引是唯一的如身                 份证号,定位到一个姓名A如果存在多个人姓名为A则更新的是跟新多个人的姓名是不合理的,因为               身份证号是唯一的。

 

       如果聚集键不一定则sqlserver会在必要时添加一个隐藏的唯一标识列来保证内部的唯一性。

 

      思考索引和约束有哪些区别?

             索引会建立真实的物理结构需要维护,而索引则是逻辑上的意义。

 

     3.索引结构

 

 

 

        对于聚簇索引表的聚簇索引结构如下。

         

Sql代码   收藏代码
  1. -- 创建聚簇索引表  
  2. create table employee(  
  3.     id int not null identity,  
  4.     lastname  Nchar(30) not null,  
  5.     firstname nchar(29) not null,  
  6.     middleinit nchar(1) null,  
  7.     ssn char(11) not null,  
  8.     othercolumns char(258) not null default 'jack');  
  9.   
  10. alter table employee add constraint  employeePK primary key clustered (id)   
  11.   
  12. select * from employee  
  13.   
  14. -- 80000条  
  15. insert into employee(lastname,firstname,middleinit,ssn,othercolumns) values('','','','','')  
  16.   
  17. -- 查询索引结构  
  18. select index_depth as 'Depth'  
  19.       ,index_level as 'Level'  
  20.       ,record_count  
  21.       ,page_count  
  22.       ,avg_page_space_used_in_percent as 'pgPercentFull'  
  23.       ,min_record_size_in_bytes as 'minLen'  
  24.       ,max_record_size_in_bytes as 'maxLen'  
  25.       ,avg_record_size_in_bytes as 'avgLen'  
  26.       from sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('employee'),1,null,'detailed')  
    

 

 

Sql代码   收藏代码
  1. dbcc page ( {'dbname' | dbid}, filenum, pagenum [, printopt={0|1|2|3} ])  
  2.   
  3. The filenum and pagenum parameters are taken from the page IDs that come from various system tables and appear in DBCC or other system error messages. A page ID of, say, (1:354) has filenum = 1 and pagenum = 354.  
  4.   
  5. The printopt parameter has the following meanings:  
  6.   
  7. 0 - print just the page header  
  8. 1 - page header plus per-row hex dumps and a dump of the page slot array (unless its a page that doesn't have one, like allocation bitmaps)  
  9. 2 - page header plus whole page hex dump  
  10. 3 - page header plus detailed per-row interpretation  
  11.   
  12. database consistenecy checker,简称dbcc  
  13. Trace flag 3604 is to print the output in query window.   
  14.     Since you have not given -1 parameter (DBCC TRACEON(6304,-1)),   
  15.     it would be session specific. Once you close the window, it would be cleared.   

 

 

 

Sql代码   收藏代码
  1. --  寻找12345的记录。  
  2. --创建临时表  
  3. create table temp_table(  
  4.     PageFID tinyint,  
  5.     pagePID int ,  
  6.     IAMFID tinyint,  
  7.     IAMPID int,  
  8.     objectID int,  
  9.     indexID tinyint,  
  10.     partitionNumber tinyint,  
  11.     partitionID bigint,  
  12.     iam_chain_type varchar(30),  
  13.     pagetype tinyint,  
  14.     indexLevel tinyint,  
  15.     nextpageFID tinyint,  
  16.     nextpagePID int,  
  17.     prePageFID tinyint,  
  18.     prepagePID int,  
  19.     primary key(PageFID,PagepID)  
  20. )  
  21.   
  22. --寻找索引id  
  23. select * from sys.sysindexes where name='employeePK'  
  24. --查询dbcc ind结果集  
  25. --此处需要索引ID  
  26. truncate table temp_table  
  27. insert temp_table   
  28.     exec ('dbcc ind (test,employee,1)')    
  29.   
  30.   
  31.   
  32.   
  33. -- 找到根页  
  34. select indexLevel,  
  35.        PageFID,  
  36.        pagePID,  
  37.        prePageFID,  
  38.        prepagePID,  
  39.        nextpageFID,  
  40.        nextpagePID  
  41.      from temp_table  
  42.         order by indexLevel desc,prepagePID  
  43.   
  44. --查询根页的记录开始B树搜索  
  45. --LEVEL 2  
  46. dbcc page('test',1,1695,3)  
  47.   
  48. --LEVEL 1  
  49. dbcc page('test',1,1966,3)  
  50.   
  51. --LEVEL 0  
  52. dbcc traceon(3604)  
  53. dbcc page('test',1,1690,3)  
 

 

    根据索引名称获取索引ID

 

 


 根据索引ID找到级别2的Root页号 


 

    查询级别2的页内容,定位级别1的页号。

     


根据级别1的页号,查询级别1的内容,定位叶子节点的页号。 

 

 


根据叶子节点的页号,查询叶子节点的内容。 

     

 

 

    

 

 

 

 

 

 

 

 聚簇索引表的非聚簇索引结构。

    

Sql代码   收藏代码
  1. -- 修改原来的聚簇索引表结构  
  2. update employee set ssn = CAST(id as char(8))+'ssn'  
  3.   
  4. --添加UK索引  
  5. alter table employee add constraint employeeSSNUK unique nonclustered (ssn)  
  6.   
  7. --还是查找12345  
  8. -- 查询索引结构    
  9. select index_depth as 'Depth'    
  10.       ,index_level as 'Level'    
  11.       ,record_count    
  12.       ,page_count    
  13.       ,avg_page_space_used_in_percent as 'pgPercentFull'    
  14.       ,min_record_size_in_bytes as 'minLen'    
  15.       ,max_record_size_in_bytes as 'maxLen'    
  16.       ,avg_record_size_in_bytes as 'avgLen'    
  17.       from sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('employee'),2,null,'detailed')  
  18.   
  19.   
  20. --寻找索引ID  2  
  21. select * from sys.sysindexes where name='employeeSSNUK'  
  22.   
  23. -- 查询结果集  
  24. truncate table temp_table  
  25. insert temp_table   
  26.     exec ('dbcc ind (test,employee,2)')    
  27.       
  28. -- 找到根页fID,pageID  
  29. select indexLevel,  
  30.        PageFID,  
  31.        pagePID,  
  32.        prePageFID,  
  33.        prepagePID,  
  34.        nextpageFID,  
  35.        nextpagePID  
  36.      from temp_table  
  37.         order by indexLevel desc,prepagePID  
  38.   
  39. --查询根页内容找到叶子节点的页号  
  40. dbcc page('test',1,13216,3)  
  41.   
  42. --查询叶子节点的内容 存储的是聚集键  
  43. dbcc traceon(3604)    
  44. dbcc page('test',1,9037,3)    
 

 

    查询索引结构

   

 

查询索引ID

 

寻找根页号需要fID和pageID


 

查询根页内容,根据范围寻找叶子节点的页号。


 

 

 

 查询叶子节点的内容。

 



 

 

 

 

 

关于堆表索引结构

 

Sql代码   收藏代码
  1. --创建堆表  
  2. create table employeeHeap(  
  3.     id int not null identity,  
  4.     lastname  Nchar(30) not null,  
  5.     firstname nchar(29) not null,  
  6.     middleinit nchar(1) null,  
  7.     ssn char(11) not null,  
  8.     othercolumns char(258) not null default 'jack');  
  9.       
  10.  alter table employeeHeap add constraint employeeHeapPK primary key nonclustered (id)  
  11.   
  12. --查询索引ID  
  13. select * from sys.sysindexes where name='employeeHeapPK'  
  14.   
  15. -- 查询索引的结构  
  16. select index_depth as 'Depth'  
  17.       ,index_level as 'Level'  
  18.       ,record_count  
  19.       ,page_count  
  20.       ,avg_page_space_used_in_percent as 'pgPercentFull'  
  21.       ,min_record_size_in_bytes as 'minLen'  
  22.       ,max_record_size_in_bytes as 'maxLen'  
  23.       ,avg_record_size_in_bytes as 'avgLen'  
  24.       from sys.dm_db_index_physical_stats(DB_ID('test'),OBJECT_ID('employeeHeap'),3,null,'detailed')  
  25.         
  26.         
  27. truncate table temp_table  
  28. insert temp_table   
  29.     exec ('dbcc ind (test,employeeHeap,3)')    
  30.       
  31. -- 查找12345 步骤  
  32. -- 找到根页  
  33. select indexLevel,  
  34.        PageFID,  
  35.        pagePID,  
  36.        prePageFID,  
  37.        prepagePID,  
  38.        nextpageFID,  
  39.        nextpagePID  
  40.      from temp_table  
  41.         order by indexLevel desc,prepagePID  
  42.           
  43. --level 1   7888  
  44. dbcc page('test',1,7888,3)  
  45.   
  46. --查看叶节点的内容  
  47. dbcc page('test',1,7830,3)  
  48.   
  49. -- 创建解析函数  
  50. create function convert_rids (@rid binary(8))   
  51.     returns varchar(30)  
  52. as  
  53.     begin  
  54.     return (  
  55.         convert (varchar(5),  
  56.             convert(int,substring(@rid,6,1)  
  57.             +substring(@rid,5,1)))  
  58.             +':'+  
  59.             convert(varchar(10),convert(int,substring(@rid,4,1) +substring(@rid,3,1)+substring(@rid,2,1)+substring(@rid,1,1)))  
  60.             +':'+  
  61.             convert(varchar(5),convert(int,substring(@rid,8,1)+substring(@rid,7,1)))  
  62.         )  
  63.     end  
  64.   
  65. --fileID,pageID,slotNum  解析rid   
  66. select test.dbo.convert_rids(0x5126000001000400)  
  67.   
  68. --查看行的内容  
  69. dbcc traceon(3604)      
  70. dbcc page('test',1,9809,3)  
  71.   
  72.       
 

 

    查询索引ID

    

 

  根据索引ID查看索引结构

  

 

 


 根据索引ID获取根页号


 

查看根页的内容获取子节点的fID和pageID


 

 

根据根页提供的pageID查看叶子节点的内容

叶子节点存储的是物理行号,

 

 


 解析行号。


 

 

 

查看行数据。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值