• SQL索引及表的页的逻辑顺序与物理顺序


    1、经过测试发现当聚集索引新建或者重建时,会按照逻辑顺序重新排列数据页和数据页内的数据行的物理顺序。

    2、但修改表时,无论是聚集索引还是堆的数据页都是按自然顺序向后插入数据,页面上的偏移量可以证明。因为数据库的最小读取单元是页,所以页内的物理顺序无关紧要,只需要维护好页内数据的逻辑顺序。

          聚集表中插入数据时会根据索引找到相应数据页进行自然顺序插入(内部填充因子,使得数据页保留一定的空闲空间),

       如果数据页满,将分页(数据按一定比例挪到新数据页,插入行在挪动完毕后自然顺序插入。新页的物理顺序与逻辑顺序可能不一致)。

    3、然后聚集索引的数据页和索引页的逻辑顺序会调整,可以通过dbcc page 的row offset array(slot array)证明。

    4、基于以上理论,碎片的产生就合理了。因为是逻辑上的调整,所以当在表中插入数据时,可能或产生物理顺序与逻辑顺序不一致的页面。

    5、基于第一点,当表的碎片大时,可以选择重建索引。

    6、索引有重建和重组之分。碎片有外部碎片(数据在插入,更新等操作时,索引的逻辑顺序与物理顺序不一致)和内部碎片(由于页面拆分时产生,由填充因子控制)之分。

     ----------------------------------------------------

    实验涉及到的命令:

    DBCC IND ( { 'dbname' | dbid }, { 'objname' | objid },
          { nonclustered indid | 1 | 0 | -1 | -2 } [, partition_number] )

    获取页号,文件号,页数(每一条数据代表一页)

    --   1:显示所有分页的信息,包括IAM分页,数据分页,所有存在的LOB分页和行溢出页,索引分页
    --  -1: 显示所有IAM、数据分页、及指定对象上全部索引的索引分页.
    --  -2: 显示指定对象的所有IAM分页
    ---  nonclustered indid:显示所有的IAM、数据分页以及一个索引的索引分页信息 

    ----------------------------------------------------------

    属性说明:

     46 --{'dbname'|dbid}表示数据库名或者数据库ID
     47 --
     48 --{'objectname'|objectID}表示对象名或者对象ID
     49 --
     50 --{nonclustered indid|1|0|-1|-2}表示显示行内数据分页及指定对象的行内IAM分页信息
     51 --
     52 --  1:显示所有分页的信息,包括IAM分页,数据分页,所有存在的LOB分页和行溢出页,索引分页
     53 --
     54 -- -1: 显示所有IAM、数据分页、及指定对象上全部索引的索引分页.
     55 --
     56 -- -2: 显示指定对象的所有IAM分页
     57 --
     58 -- nonclustered indid:显示所有的IAM、数据分页以及一个索引的索引分页信息。
     59 --
     60 -- {partition_number}->可选,为了与中的DBCC IND命令向前兼容.它指定了一个特定分区号,如果不指定,显示所有分区的信息。
      
     --以下是DBCC IND命令输出结果的字段描述:
    字段名称                   字段描述
    PageFID                    页面文件的ID
    PagePID                     页面编号
    IAMFID              管理该页面的IAM页面所在的文件ID
    IAMPID               管理该页面的IAM页面编号
    ObjectID                    表对象ID
    IndexID                索引ID,0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 大于250就是text或image字段 书本P18
    PartitionNumber        表或索引所在的分区号码
    PartitionID                包含该分页的分区ID
    iam_chain_type          该页所属分配单元类型;行内数据、行溢出数据或Lob数据
    PageType           分页类型:1:数据页面;2:索引页面;3:Lob_mixed_page;4:Lob_tree_page;10:IAM页面
    IndexLevel          索引层级,0 代表叶级别分页 ;>0 代表非叶级别层次; NULL 代表IAM分页
    NextPageFID            本层下一个分页所在的文件ID
    NextPageFID               本层下一个分页ID 
    PrevPageFID          本层上一个分页所在的文件ID 
    PrevPageFID                本层上一个分页ID

    --必须启用此表示才能查看page的详细情况
    dbcc traceon(3604)
    go

    -------------------------------------------------

    DBCC PAGE (
    ['database name'|database id], 
    file number, page number, 
    print option = [0|1|2|3] )

    获取页内行数据的偏移量

    第一个参数是数据库名或数据库ID
    第二个参数指定文件号
    第二个参数指定页号
    Print opt参数可选; 可以使用以下值:
    0 默认值; 输出buffer header 和 page header信息
    1 输出 buffer header, page header, 分别输出每行信息, 行偏移表
    2 输出 buffer header, page header, 整页数据,  行偏移表
    3 输出 buffer header, page header, 别输出每行信息, 行偏移表; 分别列出每列的值

    ----------------------------------------------------------------------

    page属性说明:

    PAGE HEADER部分,即该页面的前96个字节。
    141 
    142 m_pageId = (1:106)              当前页面号码
    143 
    144 m_headerVersion = 1            版本号,始终为1
    145 
    146 m_type = 10                当前页面类型,m_type=1表示数据页面  10:IAM页
    147 
    148 m_typeFlagBits = 0x0         数据页和索引页为4,其他页为0
    149 
    150 m_level = 0              该页在索引页(B树)中的级数,0表示为叶子节点
    151 
    152 m_flagBits = 0x0              页面标志
    153 
    154 m_objId (AllocUnitId.idObj) = 277576027          对象id 表id
    155 
    156 m_indexId (AllocUnitId.idInd) = 1      索引ID,0 代表堆, 1 代表聚集索引, 2-250 代表非聚集索引 大于250就是text或image字段 书本P18
    157 
    158 Metadata: AllocUnitId = 299666199216128      储单元的ID,sys.allocation_units.allocation_unit_id
    159 
    160 Metadata: PartitionId = 299666199216128     数据页所在的分区号,sys.partitions.partition_id
    161 
    162 Metadata: IndexId = 1              跟m_indexId一样 对象的索引号,sys.objects.object_id&sys.indexes.index_id
    163 
    164 Metadata: ObjectId = 277576027      跟m_objId 一样     该页面所属的对象的id,sys.objects.object_id
    165 
    166 m_prevPage = (0:0)                         该数据页的前一页面
    167 
    168 m_nextPage = (0:0)                         该数据页的后一页面
    169 
    170 pminlen = 90          定长数据所占的字节数为90个字节
    171 
    172 m_slotCnt = 2    页面中的数据的行数,每页2条记录
    173 
    174 m_freeCnt = 6         页面中剩余的空间,还剩6字节的空间
    176 m_freeData = 8182     页面空闲空间的位置在8182这个位置 一个页面8KB约等于8192字节 页面空闲空间的位置在8182 
    177                       说明这个页面已经放不下数据了
    179 m_reservedCnt = 0           活动事务释放的字节数 
    
    181 m_lsn = (6:524:11) 日志记录号
    184 m_xactReserved = 0 最新加入到m_reservedCnt领域的字节数
    187 m_xdesId = (0:0) 添加到m_reservedCnt的最近的事务id
    190 m_ghostRecCnt = 0 幻影数据的行数
    193 m_tornBits = 1 页的校验位或者被由数据库页面保护形式决定页面保护位取代

    ... 行偏移数组
    8176-8177 slot7
    672-8175 空余空间  
    7 (0x7) - 607 (0x25f) 607-671  
    6 (0x6) - 542 (0x21e) 542-606  
    5 (0x5) - 467 (0x1d3) 467-541  
    4 (0x4) - 388 (0x184) 388-466  
    3 (0x3) - 309 (0x135) 309-387  
    2 (0x2) - 236 (0xec) 236-308
    1 (0x1) - 165 (0xa5) 165-235  
    0 (0x0) - 96 (0x60) 96-164
    0-95 pageheader
    DBCC 执行完毕。如果 DBCC 输出了错误信息,请与系统管理员联系。

  • 相关阅读:
    webdriver中的等待——主要讲解WebDriverWait()
    flask_sqlalchemy中的db.session.update()与db.sesssion.merge()方法的区别,db.session.query(Model)与Model.query()的区别
    Python-shutil模块
    python3-对拉钩网数据爬取及简单的数据分析
    设计模式的原则
    gcc 版本降级
    ubuntu 装机及装机以后干的事情
    ubuntu 美化
    python 抢火车票
    隔行扫描, 逐行扫描
  • 原文地址:https://www.cnblogs.com/williamjie/p/9390057.html
Copyright © 2020-2023  润新知