【Paddy】如何将物理表分割成动态数据表与静态数据表

前言  html

 

  通常来讲,物理表的增、删、改、查都受到数据量的制约,进而影响了性能。sql

 

  不少状况下,你所负责的业务关键表中,每日变更的数据库与不变更的数据量比较,相差很是大。数据库

 

  这里咱们将变更的数据称为动态数据,不变更的数据称为静态数据架构

 

  举个例子,1张1000W的表,每日动态数据只有1W条,999W条的数据都为静态。每每select或者重复改变的数据都在动态数据中。好比订单表。ide

 

  因此,若是将动态数据库从表中剥离出来,分割两张表,一张动态数据表,一张静态数据表,从数据量的角度来看,性能是否是就会天然提升了?性能

 

  下图为一张现实表和一张理想化的结构   (蓝色为静态数据:1000W、黄色为动态数据:100W):测试

  

  但愿动态数据和静态数据分割开spa

  

  

  想法再好,也比不上现实的残酷。不少朋友可能都想到这种架构,但实现起来问题很是多:3d

  

  1.  如何将动态数据自动从静态数据中剥离?如何维护?htm

  2.  程序代码改动量不可预计。尤为核心表的使用遍及各地,分割成两张表后,全部代码基本都要重构。

  3.  表分区是否能够达到一样目的,NO~由于表分区没法100%区分动态与静态,并且分区列的使用决定了效率。

 

  下面开始,进入本次主题,如何在SQL Server中达到动态数据、静态数据分割;两表数据如何自动维护;程序统一访问逻辑表名,零维护成本。

 

正文

  实现方法:利用视图 + 视图触发器

  没错,没有了~就是靠这两货,就解决了,下面咱们来看看逻辑图(画的很差,见谅)。

  

最后,让咱们来看看具体事例

 

1.  建立demo数据库,和动态表(TB_A_NEW)、历史表(TB_A_OLD)

CREATE DATABASE demo
GO
ALTER DATABASE demo ADD FILEGROUP HekatonFG CONTAINS MEMORY_OPTIMIZED_DATA;
GO
ALTER DATABASE demo ADD FILE( NAME = 'Memory', FILENAME ='C:\Memory.ndf') TO FILEGROUP [HekatonFG];
GO
CREATE TABLE TB_A_OLD
(
	id INT IDENTITY(1,1) PRIMARY KEY,
     NAME NVARCHAR(36) GO CREATE TABLE TB_A_NEW ( id INT IDENTITY(1, 1) PRIMARY KEY, NAME NVARCHAR(36) ) GO INSERT INTO TB_A_OLD SELECT Newid() GO 10

这个时候的两张表的数据以下:

 

而后,咱们为了保证动态表的新增数据的自增值是静态表的当前标识值+1,这样两表记录合并才能衔接。

DECLARE @IDENT BIGINT

SELECT @IDENT = Ident_current('TB_A_OLD') + 1

DBCC checkident('TB_A_NEW', reseed, @IDENT)

  

建立视图(View_TB_A)

CREATE VIEW [dbo].[View_TB_A]
AS
  SELECT *
  FROM   TB_A_NEW
  UNION ALL
  SELECT old.*
  FROM   TB_A_OLD old
         LEFT JOIN TB_A_NEW new
                ON old.id = new.id
  WHERE  new.NAME IS NULL

GO

建立视图触发器(Insert、Update)

USE demo

GO

CREATE TRIGGER [dbo].[TR_Insert]
ON [dbo].[View_TB_A]
INSTEAD OF INSERT
AS
  BEGIN
      SET NOCOUNT ON

      INSERT INTO TB_A_NEW
                  (NAME)
      SELECT NAME
      FROM   inserted
  END

GO

USE demo

GO

CREATE TRIGGER [dbo].[TR_Update]
ON [dbo].[View_TB_A]
INSTEAD OF UPDATE
AS
  BEGIN
      SET NOCOUNT ON

      --1. 判断update中,包含的记录是否都在new表中
      DECLARE @count BIGINT

      SELECT @count = Count(1)
      FROM   deleted

      UPDATE TB_A_NEW
      SET    NAME = b.NAME
      FROM   TB_A_NEW a,
             inserted b
      WHERE  a.id = b.id

      IF @@ROWCOUNT < @count
        BEGIN
            SET IDENTITY_INSERT TB_A_NEW ON

            INSERT INTO TB_A_NEW
                        (id,
                         NAME)
            SELECT i.id,
                   i.NAME
            FROM   inserted i
                   LEFT JOIN TB_A_NEW n
                          ON i.id = n.id
            WHERE  n.NAME IS NULL
        END
  END

GO

下面,咱们来测试下SELECT、UPDATE、INSERT

Select

SELECT的结果就是刚才的插入10条记录,经过!

 

Insert

INSERT到视图中,会在TB_A_NEW表中新增一条记录,TB_A_OLD并无任何变化。也就是自动分配到了动态表中,经过!

 

Update

而后咱们继续更新id=2的记录,看看结果如何

最后,咱们继续查询视图VIEW_TB_A,看看最终返回的结果。

看到最终结果11条,而且以前经过视图的更新,插入都返回了正确结果,经过!

 

至此,测试结束,经过视图和视图触发器,实现了统一名称访问,底册物理表分割动态表和静态表,测试过程并不包含delete,感兴趣的童鞋稍微琢磨下就出来了。

 

若是须要合并动态表与静态表,只需将id相同记录,更新到静态表,静态表不存在的id对应动态数据,插入到静态表中便可。

本次内容主意在实现方法,具体性能提高测试,往后再作说明,简单说下,就是触发器的逻辑处理,放在了物理表插入数据以前。将数据分类存储。因此逻辑处理开销会增长,可是物理存储分割。在数据量影响性能明显的场景中会很是适用。

若是你的数据库是SQL Server 2014,那么将静态和动态表定义到内存表中,动态数据又剥离了,具体提高多少这里不作猜想,有环境的朋友能够试试哦~

 

另:

  利用以上方法,也能够解决肖桑(大菠萝)和笑东风提到的的主键int修改成bigint型问题

  (http://www.cnblogs.com/TeyGao/p/4463389.html)

      若是每日一次合并动态表与静态表数据,动态数据表就是当日的差别数据哦,扩展使用很是方便。

 

好~就到这里,再见吧~

相关文章
相关标签/搜索