Replication的犄角旮旯(三)--聊聊@bitmap

系统 1954 0
原文: Replication的犄角旮旯(三)--聊聊@bitmap

 

 

《Replication的犄角旮旯》系列导读

Replication的犄角旮旯(一)--变更订阅端表名的应用场景

Replication的犄角旮旯(二)--寻找订阅端丢失的记录

Replication的犄角旮旯(三)--聊聊@bitmap

Replication的犄角旮旯(四)--关于事务复制的监控

Replication的犄角旮旯(五)--关于复制identity列

Replication的犄角旮旯(六)-- 一个DDL引发的血案(上)(如何近似估算DDL操作进度)

Replication的犄角旮旯(七)-- 一个DDL引发的血案(下)(聊聊logreader的延迟)

Replication的犄角旮旯(八)-- 订阅与发布异构的问题

Replication的犄角旮旯(九)-- sp_setsubscriptionxactseqno,赋予订阅活力的工具

---------------------------------------华丽丽的分割线--------------------------------------------

 

关于replication中的bitmap,貌似介绍的文档不多;本文将从对此参数做一初步的简析,并介绍如何利用这个参数处理一些特定环境下的问题;

再次强调, 本方法虽多次经受验证无误,但多次被MS supporter们建议不要尝试使用此方法,还望各位DBA三思!

先来看看@bitmap在哪里出现

  我们先创建一个表的复制订阅,表结构如下

        
           1
        
        
          USE
        
        
          [
        
        
          test_aaa
        
        
          ]
        
        
           2
        
        
          GO
        
        
           3
        
        
           4
        
        
          /*
        
        
          ***** Object:  Table [dbo].[test_b]    Script Date: 2014/1/23 16:12:28 *****
        
        
          */
        
        
           5
        
        
          SET
        
         ANSI_NULLS 
        
          ON
        
        
           6
        
        
          GO
        
        
           7
        
        
           8
        
        
          SET
        
         QUOTED_IDENTIFIER 
        
          ON
        
        
           9
        
        
          GO
        
        
          10
        
        
          11
        
        
          SET
        
         ANSI_PADDING 
        
          ON
        
        
          12
        
        
          GO
        
        
          13
        
        
          14
        
        
          CREATE
        
        
          TABLE
        
        
          [
        
        
          dbo
        
        
          ]
        
        .
        
          [
        
        
          test_b
        
        
          ]
        
        
          (


        
        
          15
        
        
          [
        
        
          id1
        
        
          ]
        
        
          [
        
        
          int
        
        
          ]
        
        
          NOT
        
        
          NULL
        
        
          ,


        
        
          16
        
        
          [
        
        
          id2
        
        
          ]
        
        
          [
        
        
          int
        
        
          ]
        
        
          NOT
        
        
          NULL
        
        
          ,


        
        
          17
        
        
          [
        
        
          id3
        
        
          ]
        
        
          [
        
        
          int
        
        
          ]
        
        
          NOT
        
        
          NULL
        
        
          ,


        
        
          18
        
        
          [
        
        
          id4
        
        
          ]
        
        
          [
        
        
          int
        
        
          ]
        
        
          NOT
        
        
          NULL
        
        
          ,


        
        
          19
        
        
          [
        
        
          name
        
        
          ]
        
        
          [
        
        
          varchar
        
        
          ]
        
        (
        
          10
        
        ) 
        
          NULL
        
        
          ,


        
        
          20
        
        
          [
        
        
          remark1
        
        
          ]
        
        
          [
        
        
          varchar
        
        
          ]
        
        (
        
          100
        
        ) 
        
          NULL
        
        
          ,


        
        
          21
        
        
          [
        
        
          remark2
        
        
          ]
        
        
          [
        
        
          varchar
        
        
          ]
        
        (
        
          100
        
        ) 
        
          NULL
        
        
          ,


        
        
          22
        
        
          [
        
        
          remark3
        
        
          ]
        
        
          [
        
        
          varchar
        
        
          ]
        
        (
        
          100
        
        ) 
        
          NULL
        
        
          ,


        
        
          23
        
        
          [
        
        
          remark4
        
        
          ]
        
        
          [
        
        
          varchar
        
        
          ]
        
        (
        
          100
        
        ) 
        
          NULL
        
        
          ,


        
        
          24
        
        
          CONSTRAINT
        
        
          [
        
        
          pk_id1_id2_id3_id4
        
        
          ]
        
        
          PRIMARY
        
        
          KEY
        
        
          CLUSTERED
        
        
          25
        
        
          (


        
        
          26
        
        
          [
        
        
          id1
        
        
          ]
        
        
          ASC
        
        
          ,


        
        
          27
        
        
          [
        
        
          id2
        
        
          ]
        
        
          ASC
        
        
          ,


        
        
          28
        
        
          [
        
        
          id3
        
        
          ]
        
        
          ASC
        
        
          ,


        
        
          29
        
        
          [
        
        
          id4
        
        
          ]
        
        
          ASC
        
        
          30
        
         )
        
          WITH
        
         (PAD_INDEX 
        
          =
        
        
          OFF
        
        , STATISTICS_NORECOMPUTE 
        
          =
        
        
          OFF
        
        , IGNORE_DUP_KEY 
        
          =
        
        
          OFF
        
        , ALLOW_ROW_LOCKS 
        
          =
        
        
          ON
        
        , ALLOW_PAGE_LOCKS 
        
          =
        
        
          ON
        
        ) 
        
          ON
        
        
          [
        
        
          PRIMARY
        
        
          ]
        
        
          31
        
         ) 
        
          ON
        
        
          [
        
        
          PRIMARY
        
        
          ]
        
        
          32
        
        
          33
        
        
          GO
        
        
          34
        
        
          35
        
        
          SET
        
         ANSI_PADDING 
        
          OFF
        
        
          36
        
        
          GO
        
      
View Code

  到订阅库的存储过程中,找到sp_MSupd_dbotest_b,生成脚本

        
           1
        
        
          USE
        
        
          [
        
        
          test_byxl1
        
        
          ]
        
        
           2
        
        
          GO
        
        
           3
        
        
          /*
        
        
          ***** Object:  StoredProcedure [dbo].[sp_MSupd_dbotest_b]    Script Date: 2014/1/23 14:28:46 *****
        
        
          */
        
        
           4
        
        
          SET
        
         ANSI_NULLS 
        
          ON
        
        
           5
        
        
          GO
        
        
           6
        
        
          SET
        
         QUOTED_IDENTIFIER 
        
          ON
        
        
           7
        
        
          GO
        
        
           8
        
        
          ALTER
        
        
          procedure
        
        
          [
        
        
          dbo
        
        
          ]
        
        .
        
          [
        
        
          sp_MSupd_dbotest_b
        
        
          ]
        
        
           9
        
        
          @c1
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          10
        
        
          @c2
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          11
        
        
          @c3
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          12
        
        
          @c4
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          13
        
        
          @c5
        
        
          varchar
        
        (
        
          10
        
        ) 
        
          =
        
        
          NULL
        
        
          ,     


        
        
          14
        
        
          @c6
        
        
          varchar
        
        (
        
          100
        
        ) 
        
          =
        
        
          NULL
        
        
          ,     


        
        
          15
        
        
          @c7
        
        
          varchar
        
        (
        
          100
        
        ) 
        
          =
        
        
          NULL
        
        
          ,     


        
        
          16
        
        
          @c8
        
        
          varchar
        
        (
        
          100
        
        ) 
        
          =
        
        
          NULL
        
        
          ,     


        
        
          17
        
        
          @c9
        
        
          varchar
        
        (
        
          100
        
        ) 
        
          =
        
        
          NULL
        
        
          ,     


        
        
          18
        
        
          @pkc1
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          19
        
        
          @pkc2
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          20
        
        
          @pkc3
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          21
        
        
          @pkc4
        
        
          int
        
        
          =
        
        
          NULL
        
        
          ,     


        
        
          22
        
        
          @bitmap
        
        
          binary
        
        (
        
          2
        
        
          )


        
        
          23
        
        
          as
        
        
          24
        
        
          begin
        
        
          25
        
        
          if
        
         (
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          1
        
        
          =
        
        
          1
        
        ) 
        
          or
        
        
          26
        
                (
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          2
        
        
          =
        
        
          2
        
        ) 
        
          or
        
        
          27
        
                (
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          4
        
        
          =
        
        
          4
        
        ) 
        
          or
        
        
          28
        
                (
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          8
        
        
          =
        
        
          8
        
        
          )


        
        
          29
        
        
          begin
        
        
          30
        
        
          update
        
        
          [
        
        
          dbo
        
        
          ]
        
        .
        
          [
        
        
          test_b
        
        
          ]
        
        
          31
        
        
          set
        
        
          [
        
        
          id1
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          1
        
        
          when
        
        
          1
        
        
          then
        
        
          @c1
        
        
          else
        
        
          [
        
        
          id1
        
        
          ]
        
        
          end
        
        
          ,


        
        
          32
        
        
          [
        
        
          id2
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          2
        
        
          when
        
        
          2
        
        
          then
        
        
          @c2
        
        
          else
        
        
          [
        
        
          id2
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          33
        
        
          [
        
        
          id3
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          4
        
        
          when
        
        
          4
        
        
          then
        
        
          @c3
        
        
          else
        
        
          [
        
        
          id3
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          34
        
        
          [
        
        
          id4
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          8
        
        
          when
        
        
          8
        
        
          then
        
        
          @c4
        
        
          else
        
        
          [
        
        
          id4
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          35
        
        
          [
        
        
          name
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          16
        
        
          when
        
        
          16
        
        
          then
        
        
          @c5
        
        
          else
        
        
          [
        
        
          name
        
        
          ]
        
        
          end
        
        
          ,


        
        
          36
        
        
          [
        
        
          remark1
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          32
        
        
          when
        
        
          32
        
        
          then
        
        
          @c6
        
        
          else
        
        
          [
        
        
          remark1
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          37
        
        
          [
        
        
          remark2
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          64
        
        
          when
        
        
          64
        
        
          then
        
        
          @c7
        
        
          else
        
        
          [
        
        
          remark2
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          38
        
        
          [
        
        
          remark3
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          128
        
        
          when
        
        
          128
        
        
          then
        
        
          @c8
        
        
          else
        
        
          [
        
        
          remark3
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          39
        
        
          [
        
        
          remark4
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          2
        
        ,
        
          1
        
        ) 
        
          &
        
        
          1
        
        
          when
        
        
          1
        
        
          then
        
        
          @c9
        
        
          else
        
        
          [
        
        
          remark4
        
        
          ]
        
        
          end
        
        
          40
        
        
          where
        
        
          [
        
        
          id1
        
        
          ]
        
        
          =
        
        
          @pkc1
        
        
          and
        
        
          [
        
        
          id2
        
        
          ]
        
        
          =
        
        
          @pkc2
        
        
          and
        
        
          [
        
        
          id3
        
        
          ]
        
        
          =
        
        
          @pkc3
        
        
          and
        
        
          [
        
        
          id4
        
        
          ]
        
        
          =
        
        
          @pkc4
        
        
          41
        
        
          if
        
        
          @@rowcount
        
        
          =
        
        
          0
        
        
          42
        
        
          if
        
        
          @@microsoftversion
        
        
          >
        
        
          0x07320000
        
        
          43
        
        
          exec
        
         sp_MSreplraiserror 
        
          20598
        
        
          44
        
        
          end
        
        
          45
        
        
          else
        
        
          46
        
        
          begin
        
        
          47
        
        
          update
        
        
          [
        
        
          dbo
        
        
          ]
        
        .
        
          [
        
        
          test_b
        
        
          ]
        
        
          48
        
        
          set
        
        
          [
        
        
          name
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          16
        
        
          when
        
        
          16
        
        
          then
        
        
          @c5
        
        
          else
        
        
          [
        
        
          name
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          49
        
        
          [
        
        
          remark1
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          32
        
        
          when
        
        
          32
        
        
          then
        
        
          @c6
        
        
          else
        
        
          [
        
        
          remark1
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          50
        
        
          [
        
        
          remark2
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          64
        
        
          when
        
        
          64
        
        
          then
        
        
          @c7
        
        
          else
        
        
          [
        
        
          remark2
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          51
        
        
          [
        
        
          remark3
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          1
        
        ,
        
          1
        
        ) 
        
          &
        
        
          128
        
        
          when
        
        
          128
        
        
          then
        
        
          @c8
        
        
          else
        
        
          [
        
        
          remark3
        
        
          ]
        
        
          end
        
        
          ,     


        
        
          52
        
        
          [
        
        
          remark4
        
        
          ]
        
        
          =
        
        
          case
        
        
          substring
        
        (
        
          @bitmap
        
        ,
        
          2
        
        ,
        
          1
        
        ) 
        
          &
        
        
          1
        
        
          when
        
        
          1
        
        
          then
        
        
          @c9
        
        
          else
        
        
          [
        
        
          remark4
        
        
          ]
        
        
          end
        
        
          53
        
        
          where
        
        
          [
        
        
          id1
        
        
          ]
        
        
          =
        
        
          @pkc1
        
        
          and
        
        
          [
        
        
          id2
        
        
          ]
        
        
          =
        
        
          @pkc2
        
        
          and
        
        
          [
        
        
          id3
        
        
          ]
        
        
          =
        
        
          @pkc3
        
        
          and
        
        
          [
        
        
          id4
        
        
          ]
        
        
          =
        
        
          @pkc4
        
        
          54
        
        
          if
        
        
          @@rowcount
        
        
          =
        
        
          0
        
        
          55
        
        
          if
        
        
          @@microsoftversion
        
        
          >
        
        
          0x07320000
        
        
          56
        
        
          exec
        
         sp_MSreplraiserror 
        
          20598
        
        
          57
        
        
          end
        
        
          58
        
        
          end
        
      
View Code

  看到这么多@bitmap,是不是有种升仙的感觉?

  @bitmap 是binary类型,即二进制串;简单来说,它是用来表示所操作的字段位置的参数,通过@bitmap,分发代理从distribution.dbo.msrepl_commands中读取命令时(update操作),才会知道哪些列进行了更新;

  我们先来解析一下这个存储过程;

1、根据表结构的code,我们知道这个表共有9个字段,其中id1~id4被定义为联合主键;

     由于binary(1)表示1个字节(8位的2进制),因此我们表示9个字段的@bitmap就只能用binary(2)来容纳了;

  其次,有的童鞋说,他们看到的update存储过程只有一个程序段,而我的例子中有两部分(29行~44行、46行~57行)。这个是由于存在联合主键造成的;即当被订阅的表中含有联合主键(2个或以上的字段一同作为主键)的时候才会出现两段代码,前者是更新主键列,后者则是更新非主键列;

2、根据更新列的位置不同,@bitmap中的对应的值也不同;

   substring(@bitmap,1,1) & 1 = 1 表示第一列有更新;

   substring(@bitmap,1,1) & 2 = 2 表示第二列有更新;

   substring(@bitmap,1,1) & 4 = 4 表示第三列有更新;

     以此类推

   substring(@bitmap,1,1) & 128 = 128 表示第八列有更新;

     那第九位呢?  =256么?  由于1个字节只有8位,而128=2^7,当第九位出现时就要进位了

   substring(@bitmap,2,1) & 1 = 1

     怎么样,不难理解吧?

定义4个字段的联合主键只是为了举例说明的时候方便一些,实际的生产环境中可能不太经常能遇到;

 

再来看一下@bitmap在哪里可以获取到呢?我先更新一条记录,更新之前先关闭相应的分发代理(此处不需要分发命令应用到订阅端)

我们去distribution里看看具体的分发命令(具体做法请见《 Replication的犄角旮旯(二)--寻找订阅端丢失的记录 》)

从命令中我们可以看出,更新的列位置为第5(name)、7(remark2)、8(remark3)列,按照二进制的表示方法为(注意反取,即←表示第1至第9位)

0 1101 0000

由于第九位没有更新,因此为0,所以bitmap就是 1101 0000,换成十六进制就是0xD0,由于bitmap超出1个字节,因此后面再补0,就是我们看到的0xd000了

可能看到这里,有些童鞋会说,这太麻烦了,遇到一个很宽的表,光数逗号就数死了……尽管我们明白逗号是为了分割字段的,但系统为什么会这样生成呢,这个问题可以参考: http://msdn.microsoft.com/zh-cn/library/ms152489%28v=sql.120%29.aspx

这个和article的属性,调用订阅端存储过程方式有关(SCALL),这个不是本文的重点,在此不做赘述;

 

根据上面的算法,我们就可以知道,当我们要更新一个表时,可以根据更新列的位置,推算出实际的bitmap值,但这又有什么用呢?

 

-------------------------------------我是华丽丽的分割线-------------------------------------

 

应用场景:一个表(还是说商品表吧,比较典型),保存商品信息、简介等内容,都是varchar(max)或text类型;商家在促销活动前通常会大批量的更新这些内容(比如加个促销活动介绍等等),更新大字段是复制环境中最头疼的问题;

由于一条复制命令有长度限制(1K左右),如果一条更新记录中的更新内容过大,就会被拆分成多条命令写到msrepl_commands中(我曾经碰到过1条记录的更新操作被拆成100个复制命令),如果高峰时期有用户大量的进行这种操作,那作为DBA就可以升级为“张三疯”了;

这时候我们就可以根据具体的update命令(一般除了更新必要的字段外,还会捎带更新updatetime这样的时间戳,具体就去找研发兄弟们要吧),计算出相应的bitmap,然后在相应的存储过程中加个判断,屏蔽掉这样的操作;

具体操作就是,在sp_MSupd_dbotest_b这里的第24、25行之间加上

if @bitmap=0xd000

return;

再打开分发代理,这样就屏蔽了@bitmap=0xd000的全部操作;

按照前面的操作,并没有进行下面的更新

而我在此之后又从发布服务器insert了一条主键为2,2,2,2的记录,以证明该操作在update之后已经传到了订阅端,而update被屏蔽了;

需要注意的是,由于按位操作是绝对严格,对于只更新column1和同时更新column1、column2将产生不同的bitmap,操作时一定要谨慎;

 

 

Replication的犄角旮旯(三)--聊聊@bitmap


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论