SqlServer 垂直分表(减少程序改动)

由于sqlserver的设计特殊性,一般大量数据一般都是采用水平分表,而垂直分表只是把text、图片都较大数据放到单独的表中,这样数据设计会更合理,相对于mysql可能要好一点,mssql本来就是一个文件,基本上提升不大,目前来看几十万的数据没有分不分表没有任何影响,对于千万以上数据还是采用水平分表比较好。

而 垂直分表 则相对很少见到和用到,因为这可能是数据库设计上的问题了。如果数据库中一张表有部分字段几乎从不不更改但经常查询,而部分字段的数据频繁更改,这种设计放到同一个表中就不合理了,相互影响太大了。在已存在改情况的表的时候,可以考虑按列拆分表,即垂直拆分。

由于垂直分表的案例比较少,最近因为存在这样的表,所以个人捣鼓了一下。

源表设计结构:

--  源表
CREATE TABLE [dbo].[DemoTab](
[Guid] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](30) NOT NULL,
[Password] [nvarchar](30) NOT NULL,
[UserAccount] [varchar](30) NOT NULL,
[Amount] [numeric](18, 4) NULL,
CONSTRAINT [PK_DemoTab] PRIMARY KEY CLUSTERED ([Guid])
)
GO

ALTER TABLE [dbo].[DemoTab]
ADD CONSTRAINT [DF_DemoTab_Guid] DEFAULT (newsequentialid()) FOR [Guid]
GO

--  原来是访问视图的(好处就是视图层不变)
CREATE VIEW [dbo].[VDemoTab]
AS
SELECT [Guid],[UserName],[Password],[UserAccount],[Amount]
FROM [dbo].[DemoTab]
GO

注:拆分后各表的主键都是相同了,而且拆分后的表是规范化的。

现在拆成两张表:

注意选择一张表作为基表,其他表都有与该表的外键。

--  分表【1】,以该表为"主表",其他拆分出的表为"子表"
CREATE TABLE [dbo].[DemoTab001](
[Guid] [uniqueidentifier] NOT NULL,
[UserName] [nvarchar](30) NOT NULL,
[Password] [nvarchar](30) NOT NULL,
CONSTRAINT [PK_DemoTab001] PRIMARY KEY CLUSTERED ([Guid])
)
GO

--  主键默认值可以不需要,因为插入数据前需要确定主键值
--ALTER TABLE [dbo].[DemoTab001]
--ADD CONSTRAINT [DF_DemoTab001_Guid] DEFAULT (newsequentialid()) FOR [Guid]
--GO

--  分表【2】,"子表"
CREATE TABLE [dbo].[DemoTab002](
[Guid] [uniqueidentifier] NOT NULL,
[UserAccount] [varchar](30) NOT NULL,
[Amount] [numeric](18, 4) NULL,
CONSTRAINT [PK_DemoTab002] PRIMARY KEY CLUSTERED ([Guid])
)
GO

--  主键默认值可以不需要,因为插入数据前需要确定主键值
--ALTER TABLE [dbo].[DemoTab002]
--ADD CONSTRAINT [DF_DemoTab002_Guid] DEFAULT (newsequentialid()) FOR [Guid]
--GO

--  若主表变更主键则级联更新或删除(主键通常是不更新的,也可省去 ON UPDATE CASCADE)
ALTER TABLE [dbo].[DemoTab002]
ADD CONSTRAINT [FK_DemoTab002_DemoTab001_Guid] FOREIGN KEY ([Guid])
REFERENCES [DemoTab001]([Guid]) ON UPDATE CASCADE ON DELETE CASCADE
GO

如果之前是对单个表或者视图操作,拆分之后逻辑层改动可能很多,为保持改动最小,可以用联合视图操作。怎么连接表依个人情况而定。

--  拆分后使用联合视图(INNER JOIN 也可以)
ALTER VIEW [dbo].[VDemoTab]
AS
SELECT T1.[Guid],T1.[UserName],T1.[Password],T2.[UserAccount],T2.[Amount]
FROM [dbo].[DemoTab001] T1 LEFT JOIN [dbo].[DemoTab002] T2 ON T1.[Guid]=T2.[Guid]
GO

这时问题来了,要对表进行DML操作,insert , update , delete 怎么解决?因为要求主键是分散在多个表并且是相同的!

这时只能用考虑触发器来保证一致性了,触发器则定义在视图上,使用的是 INSTEAD OF 类型的触发器。

insert 触发器:

视图 [VDemoTab] 中的 [Guid] 为表 插入时值,在插入触发器中,虚拟表[inserted]的[Guid]是唯一的,所以在触发器中可以同时使用该 [Guid] 插入到多个分表中,保证了多个分表的[Guid]是相同的!

--  insert 触发器
CREATE TRIGGER [dbo].[tgr_VDemoTab_insert]
ON [dbo].[VDemoTab]
INSTEAD OF INSERT
AS
BEGIN
 INSERT INTO [dbo].[DemoTab001]([Guid],[UserName],[Password])
 SELECT [Guid],[UserName],[Password] FROM inserted;

 INSERT INTO [dbo].[DemoTab002]([Guid],[UserAccount],[Amount])
 SELECT [Guid],[UserAccount],[Amount] FROM inserted;
END
GO

update 触发器:

同理,更新时涉及虚拟表 deleted 和 inserted,而更新是对视图[VDemoTab]更新的,所以虚拟表inserted包括了所有的字段,所以需要触发器分别更新多个分表。

--  update 触发器
CREATE TRIGGER [dbo].[tgr_VDemoTab_update]
ON [dbo].[VDemoTab]
INSTEAD OF UPDATE
AS
BEGIN
 UPDATE T1 SET
 T1.[UserName] = T2.[UserName],
 T1.[Password] = T2.[Password]
 FROM [dbo].[DemoTab001] AS T1, inserted AS T2 WHERE T1.[Guid] = T2.[Guid] 

 UPDATE T1 SET
 T1.[UserAccount] = T2.[UserAccount],
 T1.[Amount] = T2.[Amount]
 FROM [dbo].[DemoTab002] AS T1, inserted AS T2 WHERE T1.[Guid] = T2.[Guid]
END
GO

delete 触发器:

删除视图[VDemoTab]记录,涉及多个表则不允许删除,因此只要删除"主表"的记录即可,其他分表都会级联删除。

--  delete 触发器
CREATE TRIGGER [dbo].[tgr_VDemoTab_delete]
ON [dbo].[VDemoTab]
INSTEAD OF DELETE
AS
BEGIN
    DELETE FROM [dbo].[DemoTab001]
    WHERE [Guid] IN (SELECT [Guid] FROM deleted)
END
GO

设计基本就完成了,现在进行测试。

INSERT INTO [dbo].[VDemoTab]([Guid],[UserName],[Password],[UserAccount],[Amount])
SELECT NEWID(),'user01','pw01','account01',100
UNION ALL
SELECT NEWID(),'user02','pw02','account02',99
UNION ALL
SELECT NEWID(),'user03','pw03','account03',0
GO

UPDATE [VDemoTab] SET [Password]='pw',[Amount]='10'
WHERE [Amount] >=0 AND [Amount]<100 AND [UserName] LIKE '%3'
GO

DELETE FROM [VDemoTab] WHERE [UserName] = 'user03'
GO

SELECT * FROM [dbo].[DemoTab001]
SELECT * FROM [dbo].[DemoTab002]
SELECT * FROM [dbo].[VDemoTab]

基本操作都是正常的!垂直分表完成!

性能怎么样呢?

由于 Guid 作为主键,使用的是 NEWID() 而不是  NEWSEQUENTIALID(),新增记录时聚集索引都可能重新排序较多数据。

分表之后,单个数据页能存储的数据更多了,但是分成多个表中,数据页也增多了,同时 Guid 在每个表都存在,所以查询数据时IO会更多。

对于更新数据,在触发器中是两个表同时更新的,即使更新其中一个分表,其他分表都会影响。如果分表之后不同时更新,可以在触发器中使用 if(update(col)) 来判断更新的是那一列,就更新相应的基表就行,其他分表不更新。

最好的情况就是,拆分后的表都是“独立”的,不用联合视图,查询和更改都独立,这需要更改逻辑层。

到此这篇关于SqlServer 垂直分表(减少程序改动)的文章就介绍到这了,更多相关SqlServer 垂直分表内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SQLServer2019 数据库环境搭建与使用的实现

    目录 一.SQL Server 数据库概述 二.安装 SQL Server 2019 2.1 SQL Server 2019 安装必备条件 2.2 下载 SQL Server 2019 安装引导文件 2.3 下载 SQL Server 2019 安装文件 2.4 安装 SQL Server 2019 数据库 2.5 安装 SQL Server Management Studio 管理工具 2.6 启动 SQLServer 管理工具 数据库,顾名思义,就是一个存储数据的大仓库,涵盖了多个方面的知识

  • sqlserver2017共享功能目录路径不可改的解决方法

    注意:什么路径不可改就搜索该路径进行删除注册表记录,然后重启电脑 按 win键盘+R输入 regedit 进去注册表,点击计算机按"编辑"-->查找下一个 需要等一些时间 结果出来后把搜到的结果的项删除 删除之后  按F3继续查找下一个进行删除,删除直到搜索完毕 然后把原来安装的注册表记录查找出来删除: 把含有Microsoft SQL Server字样的都删除 删除完这个再按F3查找下一个删除 删除直到按F3显示搜索完毕 接着再搜索删除记录  MSSQL 直按F3删除到显示搜索

  • SQLServer2019配置端口号的实现

    第一次写博客,实属心血来潮.为什么要写这篇博客呢?原因如下 1.有一次我想配置数据库端口号时,找不到对应的解决方案 2.是时候有个地方可以记录一下自己做过的事情了,到时候想翻看的时候可以翻看 好了,废话不多说,直接上解决方案. 我这里呢以SQLServer2019作为示例. 第一步:打开Sql Server Configuration Manager -> SQL Server 网络配置 -> MSSQLSERVER2019(这个名称是在安装时自己输入的)-> TCP/IP 第二步:右键

  • sqlserver主键自增的实现示例

    建表,主键自增 create table aaa( id bigint identity(1,1) not null PRIMARY key, name nvarchar(255) ); navicat没办法给主键列,加identity,只能用sql建表 赋值时,identity列不能赋值,报错 一.identity的基本用法 1.含义 identity表示该字段的值会自动更新,不需要我们维护,通常情况下我们不可以直接给identity修饰的字符赋值,否则编译时会报错 2.语法 列名 数据类型

  • SQLServer2019 数据库的基本使用之图形化界面操作的实现

    目录 一.数据库.表的创建与删除 1. 创建数据库 2. 修改数据库 3. 删除数据库 4. 创建数据表 5. 删除数据表 二.数据表常见操作 1. 在表结构中添加新字段 2. 在表结构中删除字段 3. 数据表更名 三.数据的增删改查 1. 数据准备 2. 添加数据 3. 删除数据 4. 修改数据 5. 查看数据 四.数据库常用操作 1. 分离数据库 2. 附加数据库 3. 执行脚本 五.创建查询和测试查询 一.数据库.表的创建与删除 1. 创建数据库 使用可视化管理工具是创建 SQL Serv

  • C语言中操作sqlserver数据库案例教程

    本文使用c语言来对sql server数据库进行操作,实现通过程序来对数据库进行增删改查操作. 操作系统:windows 10         实验平台:vs2012  +  sql server 2008 ODBC简介:开放数据库连接(Open Database Connectivity,ODBC),主要的功能是提供了一组用于数据库访问的编程接口,其主要的特点是,如果应用程序使用ODBC做数据源,那么这个应用程序与所使用的数据库或数据库引擎是无关的,为应用程序的跨平台和可移植奠定了基础. 创建

  • SQLServer2008提示评估期已过解决方案

    打开sqlserver时提示评估期已过 解决方法: 打开sqlserver安装中心(注意:选择R2的安装中心) 选择版本升级 中途可能会出现需要重启计算机,那么请重启计算机后在进行以上操作 点击确定,然后进行下一步,直到需要输入密钥 SQL Server 2008 Developer(开发版):PTTFM-X467G-P7RH2-3Q6CG-4DMYB SQL Server 2008 Enterprise(企业版):JD8Y6-HQG69-P9H84-XDTPG-34MBB 继续进行下一步,直到

  • SQLServer 日期函数大全(小结)

    一.统计语句 1.--统计当前[>当天00点以后的数据] SELECT * FROM 表 WHERE CONVERT(Nvarchar, dateandtime, 111) = CONVERT(Nvarchar, GETDATE(), 111) ORDER BY dateandtime DESC 2.--统计本周 SELECT * FROM 表 WHERE datediff(week,[dateadd],getdate())=0 3.--统计本月 SELECT * FROM 表 WHERE da

  • SqlServer 垂直分表(减少程序改动)

    由于sqlserver的设计特殊性,一般大量数据一般都是采用水平分表,而垂直分表只是把text.图片都较大数据放到单独的表中,这样数据设计会更合理,相对于mysql可能要好一点,mssql本来就是一个文件,基本上提升不大,目前来看几十万的数据没有分不分表没有任何影响,对于千万以上数据还是采用水平分表比较好. 而 垂直分表 则相对很少见到和用到,因为这可能是数据库设计上的问题了.如果数据库中一张表有部分字段几乎从不不更改但经常查询,而部分字段的数据频繁更改,这种设计放到同一个表中就不合理了,相互影

  • Mysql的水平分表与垂直分表的讲解

    在我上一篇文章中说过,mysql语句的优化有局限性,mysql语句的优化都是围绕着索引去优化的,那么如果mysql中的索引也解决不了海量数据查询慢的状况,那么有了水平分表与垂直分表的出现(我就是记录一下自己的理解) 水平分表: 如上图所示:另外三张表表结构是一样的  只不过把数据进行分别存放在这三张表中,如果要insert 或者query 那么都需要对id进行取余 然后table名进行拼接,那么就是一张完整的table_name 但是如果我需要对name进行分表呢 或者对email呢? 那么就需

  • mysql数据库分表分库的策略

    一.先说一下为什么要分表: 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,有可能会死在那儿了.分表的目的就在于此,减小数据库的负担,缩短查询时间.日常开发中我们经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表.这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕.分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率.数据库中的数据量不一定是可控的,在未进行分

  • MySQL分表和分区的具体实现方法

    垂直分表 垂直分表就是一个包含有很多列的表拆分成多个表,比如表A包含20个字段,现在拆分成表A1和A2,两个表各十个字段(具体如何拆根据业务来选择). 优势:在高并发的情境下,可以减少表锁和行锁的次数. 劣势:在数据记录非常大的情况下,读写速度还是会遇到瓶颈. 水平分表 假如某个网站,它的数据库的某个表已经达到了上亿条记录,那么此时如果通过select去查询,在没有索引的情况下,他的查询会非常慢,那么就可以通过hash算法将这个表分成10个子表(此时每个表的 的数据量只有1000万条了). 同时

  • MySQL使用MRG_MyISAM(MERGE)实现分表后查询的示例

    数据库大数据量优化是一门很大的学问,也是做为一名开发者需要掌握的专业技能. MySQL分表方式分为垂直分表和水平分表,这两种分表形式都比较简单,简单理解垂直分表指的是:表的记录并不多,但是字段却很长,表占用空间很大,检索表的时候需要执行大量的IO,严重降低了性能.这时需要把大的字段拆分到另一个表,并且该表与原表是一对一的关系.而水平分表则是在同一个数据库内,把同一个表的数据按一定规则拆到多个表中,目的是优化单一表数据量过大而产生的性能问题,避免IO争抢并减少锁表的几率. 实现分表很简单,复杂的是

  • MySQL 分表分库怎么进行数据切分

    关系型数据库本身比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限.当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库.优化索引,做很多操作时性能仍下降严重.此时就要考虑对其进行切分了,切分的目的就在于减少数据库的负担,缩短查询时间. 数据库分布式核心内容无非就是数据切分(Sharding)以及切分后对数据的定位.整合.数据切分就是将数据分散存储到多个数据库中,使得单一数据库中的数据量变小,通过扩充主机的数量缓解单一数据库的性能问题,从而达到提升数据库操作性能的目

  • MySQL分库分表与分区的入门指南

    前言 关系型数据库比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限,当数据量和并发量起来之后,就必须对数据库进行切分了. 数据切分(sharding)的手段就是分库分表.分库分表有两方面,可能是光分库不分表,也可能是光分表不分库. 数据库分布式的核心内容无非就是数据切分,以及切分后对数据的定位.整合. 为什么要分库分表 分表 单表数据量太大时,会严重影响sql执行的性能.一般单表到达几百万的时候,性能就会相对差一些了,这时就得分表了. 分表就是把一个表的数据放到多个表中,然后查询的时候

  • springboot整合shardingjdbc实现分库分表最简单demo

    一.概览 1.1 简介 ShardingSphere-JDBC定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务. 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架. 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC. 支持任何第三方的数据库连接池,如:DBCP,

  • Java使用Sharding-JDBC分库分表进行操作

    目录 主从库搭建 Compose File Master 配置 Slave 配置 主从配置 创建分库分表 Order 1 库 Order 2 库 User 库 Sharding-JDBC 引入 Sharding-JDBC 配置 可选配置 数据源配置 主从复制配置 数据节点配置 Demo 程序 Sharding-JDBC 是无侵入式的 MySQL 分库分表操作工具,所有库表设置仅需要在配置文件中配置即可,无须修改任何代码. 本文写了一个 Demo,使用的是 SpringBoot 框架,通过 Doc

  • MySQL常用分库分表方案汇总

    目录 一.数据库瓶颈 二.分库分表 2.水平分表 3.垂直分库 4.垂直分表 三.分库分表工具 四.分库分表步骤 五.分库分表问题 1.非partition key的查询问题 2.非partition key跨库跨表分页查询问题 3.扩容问题 六.分库分表总结 一.数据库瓶颈 不管是IO瓶颈,还是CPU瓶颈,最终都会导致数据库的活跃连接数增加,进而逼近甚至达到数据库可承载活跃连接数的阈值.在业务Service来看就是,可用数据库连接少甚至无连接可用.接下来就可以想象了吧(并发量.吞吐量.崩溃).

随机推荐