使用SQL Server分区表功能提高数据库的读写性能

首先祝大家新年快乐,身体健康,万事如意。
一般来说一个系统最先出现瓶颈的点很可能是数据库。比如我们的生产系统并发量很高在跑一段时间后,数据库中某些表的数据量会越来越大。海量的数据会严重影响数据库的读写性能。
这个时候我们会开始优化系统,一般会经过这么几个过程:

  1. 找出SQL慢查询,针对该SQL进行优化,比如改进SQL的写法,查看执行计划对全表扫描的字段建立索引

  2. 引入缓存,把一部分读压力加载到内存中

  3. 读写分离

  4. 引入队列,把并发的请求使其串行化,来减轻系统瞬时压力

  5. 分表/分库

对于第五点优化方案我们来细说一下。分表分库通常有两种拆分维度:1.垂直切分,垂直切分往往跟业务有强相关关系,比如把某个表的某些不常用的字段迁移出去,比如订单的明细数据可以独立成一张表,需要使用的时候才读取 2.水平切分,比如按年份来拆分,把数据库按年或者按某些规则按时间段分成多个表。
拆分表之后每个表的数据量将会变小,带来的好处是不言而喻的。不管是全表扫描,还是索引查询都会有比较高的提升。如果把不同的表文件落在多个磁盘上那数据库的IO性能还能进一步提高。
如果纯手工拆分,比如按年份拆分成多个表,那么上层业务代码也得进行调整。每次读写都得判断该使用哪张表。如果是跨多个年份的分页查询更加难搞。人肉分表基本上不可能实现的,对于上层编码简直是个噩梦。所以针对分表分库我们通常会使用某些中间件,比如Mycat,Sharding-JDBC等中间件。使用这些组件确实能实现分表分库,并且对业务层代码屏蔽了数据库架构的改动,但是配置略显麻烦。如果你使用的是SQL Server数据库,并且目前还不需要分库,只需要分表,那么其实使用内置的分区表功能是最简单的方案。只需要打开SQL Server Management Studio简单设置几下就可以了,对于你上层应用完全是无感的,你的代码、数据库连接串都不需要改动。
以下我们通过2个简单的测试,来简单的演示下如何进行表分区操作,以及测试下分区前后性能变化。

测试写性能

我们的测试方案:新建一张logs表,按年份写入数据。2019年写入1000000数据,2020年也写入100000数据。为了加快写入的速度,每个年份并行10个线程同时写,每个线程写100000数据,一共1000000数据。然后把logs表改成分区表再用同样的方式写入2000000数据。记录耗时 比较两次的耗时。
硬件为一台14年产的笔记本,OS为win10。挂载2块硬盘,1块为5400转的机械硬盘,1块为15年加的SSD。磁盘性能可以说极为垃圾。未分区时表文件会落在机械硬盘上。

未分区情况下测试

使用脚本建表:

CREATE TABLE [dbo].[logs]([id] [uniqueidentifier] NOT NULL,[log_txt] [varchar](200) NULL,[log_time] [datetime] NULL,CONSTRAINT [PK_logs] PRIMARY KEY CLUSTERED
([id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)

新建一个控制台程序编写代码:

class Program{static void Main(string[] args){Console.WriteLine("Hello World!");Task.Run(() =>{InsertData(2019);});Task.Run(() =>{InsertData(2020);});Console.ReadLine();}static void InsertData(int year){var tasks = new List<Task>();Stopwatch sw = new Stopwatch();sw.Start();for (int i = 0; i < 10; i++){tasks.Add(Task.Run(()=> {using (var conn = new SqlConnection()){conn.ConnectionString = "Persist Security Info = False; User ID =sa; Password =dev@123; Initial Catalog =fq_test; Server =.\\mssql2016";conn.Open();int index = 0;for (int j = 0; j < 100000; j++){var logtime = new DateTime(year, new Random().Next(1, 12), new Random().Next(1, 28));conn.Execute("insert into logs2 values (newid(),'下订单',@logtime)", new{logtime});Console.WriteLine("logtime:{0} index {1}", logtime, index++);}}}));}Task.WaitAll(tasks.ToArray());sw.Stop();Console.WriteLine("Year {0} complete , total time: {1}.", year, sw.ElapsedMilliseconds);}}

写完2000000数据耗时1369454毫秒。

分区情况下进行测试

开始分区

把一个表设置为分区表大概有5个步骤:

  1. 添加文件组

  2. 在文件组添加文件

  3. 新建分区函数

  4. 新建分区方案

  5. 开始分区

以下演示下如何使用SQL SERVER Management Studio管理器进行表分区:

选中数据库=>属性=>文件组,添加group1,group2两个文件组。

选中数据库=>属性=>文件。添加file1,文件组选group1,路径选择一个文件目录。这里选择E盘data目录。添加file2,文件组选择group2,路径选择一个文件目录。这里选择X盘的data目录。这样当分区的时候数据就会落在这2个目录下。这里的路径可以选择在同一个硬盘,但是为了更高的读写性能,如果有条件建议直接指定在不同的硬盘下。

选中logs表=>存储=>创建分区,启动分区向导工具。

新建一个分区函数,点击下一步。

新建一个分区方案,点击下一步。

选择一个分区列,数据会根据该列进行水平拆分。

这里选择logtime,因为时间是比较适合水平切分的一个维度。

值得数据拆分的范围。

范围选择“右边界”。

右边界跟左边界的差异在于对边界值的处理。

右边界是<,左边界是<=,也就是包含边界值。


我们这里设置group1存储2019的数据,group2存储2020的数据。

所以group1的边界值设置为2020-01-01,group2的边界值设置为2021-01-01 。

设置完是这个样子,需要3个文件组。

当出现不在group1,group2范围内的数据就会存储在第三个文件组内。

建好分区函数、分区方案后,可以选择生成脚本或者立即执行。

这里选择“立即执行”。

当执行完成后,表里的数据会按照分区方案设置的边界分散到多个文件上。

在分区情况下进行测试

先清空logs表所有的数据,然后使用同样的代码进行测试。

测试结果显示写完2000000数据耗时:

568903毫秒。

可以看到数据库写性能大副提高,大概提高了1倍不止的性能。

这也比较符合两块磁盘同时IO的预期。

测试读性能

我们的测试方案:新建一张log2表,使用上面的代码按年份写入2000000数据。然后使用select语句同时读取2019,2020年的数据。把log表转换成分区表,重新测试select的时间。比较两次读取数据的时间。
sql语句:

select * from log2 where (logtime > '2019-05-01' and logtime < '2019-06-01') or (logtime > '2020-05-01' and logtime < '2020-06-01')

首先在未分区的表上测试查询性能,花费时间为3s。

把表按前面的方法进行分区拆分,查询花费时间为1s。

读性能大概为未分区时的3倍。

总结

经过简单的测试,SQL Server的分区表功能能大副提高数据库的读写性能。通过SQL Server Management Stduio的简单设置就可以对数据库表进行分区操作,并且对应用层的代码完全是无感的,比用分表分库中间件来说简单多了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/304756.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回顾周杰伦17年间的歌词,才知道他都唱了些什么

每当提到周杰伦的歌时&#xff0c;你首先会想到的是什么呢&#xff1f;双截棍&#xff1f;中国风&#xff1f;还是是方文山&#xff1f;或者更会有人回答说&#xff1a;根本听不清的歌词…… 回想起来&#xff0c;周杰伦的歌可以说陪伴了我们一代甚至是几代人的成长。无论是《晴…

最近公共祖先_[LeetCode] 236. 二叉树的最近公共祖先

题目链接&#xff1a; https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree难度&#xff1a;中等通过率&#xff1a;57.2%题目描述:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。百度百科中最近公共祖先的定义为&#xff1a;"对于有根树…

开启事物_《原神》全新角色甘雨登场 「浮生孰来」活动祈愿开启_新闻资讯_最新手游时评_原创手游资讯...

璃月地区的方方面面&#xff0c;都由「璃月七星」治理。由他们决议得出的策略牵动着市场的走向&#xff0c;因此每一条都要慎重再三。而会议之后&#xff0c;是谁摘录出要点&#xff0c;编入长长的条例中的&#xff0c;人们便不得而知了。璃月的千头万绪&#xff0c;就是这样被…

我遇到的单词

pros and cons支持者和反对者&#xff0c;用于辩论from scratch 从头做起转载于:https://blog.51cto.com/techfans/160809

C# 接口(Interface)

接口定义了所有类继承接口时应遵循的语法合同。接口定义了语法合同 "是什么" 部分&#xff0c;派生类定义了语法合同 "怎么做" 部分。接口定义了属性、方法和事件&#xff0c;这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口…

AI浪潮席卷而来,现在加入还来得及吗?

当你的朋友圈刚被 AlphaGo、Master 刷屏&#xff0c;没几天就听说日本有公司开始用 AI 取代员工、百度将人工智能列为未来10年最重要战略。同时一夜之间&#xff0c;似乎所有大公司都开始做无人驾驶…… 人工智能正以前所未有的速度&#xff0c;渗透、改造着各行各业。而加速这…

python数据字符_python数据清洗系列之字符串处理详解

数据清洗是一项复杂且繁琐(kubi)的工作&#xff0c;同时也是整个数据分析过程中最为重要的环节。有人说一个分析项目80%的时间都是在清洗数据&#xff0c;这听起来有些匪夷所思&#xff0c;但在实际的工作中确实如此。数据清洗的目的有两个&#xff0c;第一是通过清洗让数据可用…

networkx 画有权图_利用NetworkX画网络图

现在各种商业和开源的网络可视化的工具非常多&#xff0c;NetworkX - NetworkX是一个非常重要的网络分析工具。当然它侧重于对网络结构的分析&#xff0c;也包含了网络可视化部分。我最近由于要画一些张量网络图&#xff0c;所以找到了这个工具。另一个值得推荐的是Latex中基于…

将LINUX变成路由器

LINUX系统是一个强大的网络操作系统&#xff0c;本身就是一个出色的路由器&#xff0c;只要经过非常少的几步设置&#xff0c;就会使用LINUX系统本身成为一台出色的路由器。<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />要想使…

使用 Benchmark.NET 测试代码性能

今天&#xff0c;我们将研究如何使用Benchmark.Net来测试代码性能。借助基准测试&#xff0c;我们可以创建基准来验证所做的更改是否按预期工作并且不会导致性能下降。并非每个项目都需要进行基准测试&#xff0c;但是如果您正在开发的是NuGet程序包或通用dll&#xff0c;则很有…

python用reshape二维数组化为一维数组_Python reshape的用法及多个二维数组合并为三维数组的实例...

reshape(shape) &#xff1a; 不改变数组元素&#xff0c;返回一个shape形状的数组&#xff0c;原数组不变。是对每行元素进行处理resize(shape) &#xff1a; 与.reshape()功能一致&#xff0c;但修改原数组In [1]: a np.arange(20)#原数组不变In [2]: a.reshape([4,5])Out[2…

【直观理解】一文搞懂RNN(循环神经网络)基础篇

推荐阅读时间8min~15min 主要内容简介&#xff1a;神经网络基础、为什么需要RNN、RNN的具体结构、以及RNN应用和一些结论 1神经网络基础 神经网络可以当做是能够拟合任意函数的黑盒子&#xff0c;只要训练数据足够&#xff0c;给定特定的x&#xff0c;就能得到希望的y&#x…

IIS 7.0 的 ASP.NET 应用程序生命周期概述

本主题介绍在 IIS 7.0 集成模式下运行以及与 .NET Framework 3.0 或更高版本一起运行的 ASP.NET 应用程序的应用程序生命周期。IIS 7.0 还支持经典模式&#xff0c;其行为类似于在 IIS 6.0 中运行的 ASP.NET。有关更多信息&#xff0c;请参见 IIS 5.0 和 6.0 的 ASP.NET 应用程…

python网络运维案例代码库_OLDboy-python第八期运维教程

课程目录&#xff1a;L01-Python8期VIP视频-Day101-开课介绍02-学生介绍03-课程内容介绍04-Python的发展05-Python特性介绍及与其它语言对比06-Python安装及环境准备07-编程风格要求08-Python的数据类型和运算符09-单行和多行注释10-理解ASSIC Unicode UTF-8编码11-使用和导入模…

给新手程序员的16个工作必备小妙招,省下时间去LOL吧!

写在前面&#xff1a; 这个文章核心并不是程序优化的具体技巧&#xff0c;而是拿到一个问题如何思考和利用工具的通用方法。比如即使我们不知道 profiler 这个东西&#xff0c;通过搜索"代码 每一行 时间"也可以很快知道有这样的工具叫做 profiler&#xff0c;并且学…

c#如何识别一张图片的格式

问题窥探在有些时候&#xff0c;我们拿到了一张图片。这张图片的格式是 JPG 还是 PNG&#xff1f;是 BMP 还是只有一帧的 GIF&#xff1f;虽然在大部分情况下&#xff0c;你确实可以把一张 PNG 格式的图片保存成 JPG&#xff0c;在电脑上也能双击打开看。但如果你要写一些程序来…

xftp怎么有root权限_许多人都不懂的Linux系统里的特殊权限!!你真的了解嘛?...

有的朋友一听Linux系统文件还有特殊权限&#xff0c;那头就要爆炸了&#xff0c;那还是接着看看/tmp目录和/usr/bin/passwd文件&#xff0c;怎么回事啊&#xff01;&#xff01;&#xff01;看见没有啊&#xff01;不是应该只有rwx 吗&#xff1f;还有其他的特殊权限( s 跟t )啊…

python中abc属于字符串吗_在Python中,字符串s = 'abc',那么执行表达式s+'d'之后,s的打印结果是( )。...

【单选题】当知道条件为真,想要程序无限执行直到人为停止的话,可以需要下列哪个选项?【单选题】Python3解释器执行 for i,v in enumerate([0,1,2],2):print(i,v)和 for i,v in enumerate([0,1,2]):print(i,v)的结果,你认为对的选项是( )。【单选题】Python3解释器执行AB2C3D.l…

菜单保卫战

前几天和老公去龙之梦&#xff0c;路过米爱粥&#xff0c;只见店员们齐刷刷站成两排&#xff0c;店长在前面训话。 只听店长非常严肃的说&#xff1a;“我们的菜单是很贵的&#xff0c;大家一定要注意。不光是迎宾的事情&#xff0c;也是你们每个人的事情。要经常注意一下&…

我是怎样爬下6万共享单车数据并进行分析的(附代码)

共享经济的浪潮席卷着各行各业&#xff0c;而出行行业是这股大潮中的主要分支。如今&#xff0c;在城市中随处可见共享单车的身影&#xff0c;给人们的生活出行带来了便利。相信大家总会遇到这样的窘境&#xff0c;在APP中能看到很多单车&#xff0c;但走到那里的时候&#xff…