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

前言  

  一般来说,物理表的增、删、改、查都受到数据量的制约,进而影响了性能。

  很多情况下,你所负责的业务关键表中,每日变动的数据库与不变动的数据量比较,相差非常大。

  这里我们将变动的数据称为动态数据,不变动的数据称为静态数据。

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

  所以,如果将动态数据库从表中剥离出来,分割两张表,一张动态数据表,一张静态数据表,从数据量的角度来看,性能是不是就会自然提高了?

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

  

  希望动态数据和静态数据分割开

  

  

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

  

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

  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)

      如果每日一次合并动态表与静态表数据,动态数据表就是当日的差异数据哦,扩展使用非常方便。

好~就到这里,再见吧~

时间: 2024-08-13 09:39:29

【Paddy】如何将物理表分割成动态数据表与静态数据表的相关文章

算法学习之查找算法:静态查找表(1)顺序表查找

引言: 对查找表一般的操作有:1.查询某个"特定的"数据元素是否在查找表中:2.检索某个"特定的"数据元素的各种属性:3.在查找表中插入一个数据元素:4.从查找表中删去某个数据元素. 静态查找表的操作只包括两种:1.查找某个"特定的"数据元素是否在查找表中:2.检索某个"特定的"数据元素的各种属性: 静态查找表又有四种表现形式:顺序表的查找.有序表的查找.静态树的查找.索引顺序表的查找. 静态查找涉及的关键字类型和数据元素类型

随笔 JS 字符串 分割成字符串数组 并动态添加到指定ID的DOM 里

JS /* * 字符串 分割成字符串数组 并动态添加到指定ID的DOM 里 * @id 要插入到DOM元素的ID * * 输入值为图片URL 字符串 * */ function addImages(id){ /*字符串 变量*/ var images='{$content.pictureurl} ' ; /* console.log( images ) ;*/ /*字符串分割成字符串数组 split*/ var StringArray = images.split(','); /* consol

SQL Server 动态行转列(参数化表名、分组列、行转列字段、字段

一.本文所涉及的内容(Contents) 本文所涉及的内容(Contents) 背景(Contexts) 实现代码(SQL Codes) 方法一:使用拼接SQL,静态列字段: 方法二:使用拼接SQL,动态列字段: 方法三:使用PIVOT关系运算符,静态列字段: 方法四:使用PIVOT关系运算符,动态列字段: 扩展阅读一:参数化表名.分组列.行转列字段.字段值: 扩展阅读二:在前面的基础上加入条件过滤: 参考文献(References) 二.背景(Contexts) 其实行转列并不是一个什么新鲜的

(转)数据库表分割技术浅析(水平分割/垂直分割/库表散列)

数据库表分割技术包含以下内容:水平分割/垂直分割/库表散列.接下来将对以上分割进行详细介绍,感兴趣的朋友可以了解下,对你日后维护数据库是很有帮助的 一.水平分割 什么是水平分割?打个比较形象的比喻,在食堂吃饭的时候,只有一个窗口,排队打饭的队伍太长了,都排成S型了,这时容易让排队的人产生焦虑情绪,容易产生混乱,这时一个管理者站出来,增加多个打饭窗口,把那条长长的队伍拦腰截断成几队.更形象一点的理解,你拿一把“手术刀”,把一个大表猛的切了几刀,结果这个大表,变成了几个小表. 水平分割根据某些条件将

数据库表分割技术浅析

一.水平分割 什么是水平分割?打个比较形象的比喻,在食堂 吃饭的时候,只有一个窗口,排队打饭的队伍太长了,都排成S型了,这时容易让排队的人产生焦虑情绪,容易产生混乱,这时一个管理者站出来,增加多个打饭窗 口,把那条长长的队伍拦腰截断成几队.更形象一点的理解,你拿一把“手术刀”,把一个大表猛的切了几刀,结果这个大表,变成了几个小表. 水平分割根据某些条件将数据放到两个或多 个独立的表中.即按记录进分分割,不同的记录可以分开保存,每个子表的列数相同.水平切割将表分为多个表.每个表包含的列数相同,但是

(转载)数据库表分割技术浅析(水平分割/垂直分割/库表散列)

一.数据库表分割技术 数据库表分割技术包含以下内容: 水平分割 垂直分割 库表散列 1.1.水平分割 什么是水平分割?打个比较形象的比喻,在食堂吃饭的时候,只有一个窗口,排队打饭的队伍太长了,都排成S型了,这时容易让排队的人产生焦虑情绪,容易产生混 乱,这时一个管理者站出来,增加多个打饭窗口,把那条长长的队伍拦腰截断成几队.更形象一点的理解,你拿一把“手术刀”,把一个大表猛的切了几刀,结果这个大表,变成了几个小表. 水平分割根据某些条件将数据放到两个或多个独立的表中.即按记录进分分割,不同的记录

PHP+Mysql+easyui点击左侧tree菜单对应表名右侧动态生成datagrid加载表单数据(二)

关于tree菜单生成,参考我的另一篇博文地址tree 菜单 实现功能:点击左侧tree菜单中的table,右侧通过datagrid加载出该表对用的所有数据 难点:获取该表的所有列名,动态生成datagrid,并加载数据 解决办法: 使用tree菜单的onClick事件: $('#tree').tree( { url:'tree_getData.php', onClick:function(node){ //判断点击的节点是否是子节点是子节点就创建datagrid,否则就return打开这个节点

一种以动态库的方式使用资源表的方案

这段时间研究了一下资源表的优化方案,算是有了一些成果,在此记录下来. 先交代一下背景吧:我们的服务器把资源表放在共享内存上.这么做的原因主要是,进程core掉后再拉起时不需要重新再构建一遍资源表(构建资源表主要就是构建索引查询的数据结构,比如构建一个哈希表用于根据HeroID查询英雄配置这种).然后,考虑到同一个机器上可能部署多个进程,于是自然就想到,能否有一种机制能够让一个机器上的多个进程共享同一块资源表的内存? 一个比较直观的想法就是,让多个进程挂在同一块资源表共享内存.这样做确实是可以达到

JS中,split()用法(将字符串按指定符号分割成数组)

<!DOCTYPE html> <html> <head> <meta charset="{CHARSET}"> <title></title> </head> <body> </body> <script type="text/javascript"> //在Javascript脚本中,将字符串按指定符号进行分割成数组用split()的方法 //