位置: 编程技术 - 正文

SQL Server 高性能写入的一些经验总结(sql server 性能调优)

编辑:rootadmin
1.1.1 摘要

在开发过程中,我们不时会遇到系统性能瓶颈问题,而引起这一问题原因可以很多,有可能是代码不够高效、有可能是硬件或网络问题,也有可能是数据库设计的问题。

本篇博文将针对一些常用的数据库性能调休方法进行介绍,而且,为了编写高效的SQL代码,我们需要掌握一些基本代码优化的技巧,所以,我们将从一些基本优化技巧进行介绍。

本文目录代码中的问题 数据库性能开销使用存储过程 使用数据库事务 使用SqlBulkCopy 使用表参数 1.1.2 正文

假设,我们要设计一个博客系统,其中包含一个用户表(User),它用来存储用户的账户名、密码、显示名称和注册日期等信息。

由于时间的关系,我们已经把User表设计好了,它包括账户名、密码(注意:这里没有考虑隐私信息的加密存储)、显示名称和注册日期等,具体设计如下:

推荐整理分享SQL Server 高性能写入的一些经验总结(sql server 性能调优),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:sqlserver 高可用,sql server 性能优化,sql server性能调优实战,高性能sql语句,sqlserver 高可用,sqlserver2019性能,sql server 性能调优,sql server 性能调优,内容如对您有帮助,希望把文章链接给更多的朋友!

SQL Server 高性能写入的一些经验总结(sql server 性能调优)

图1 Users表设计

上面,我们定义了Users表,它包含账户名、密码、显示名称和注册日期等个字段,其中,ID是一个自增的主键,user_resistered用来记录用户的注册时间,它设置了默认值GETDATE()。

接下来,我们将通过客户端代码实现数据存储到Users表中,具体的代码如下:代码中的问题 上面,我们使用再普通不过的ADO.NET方式实现数据写入功能,但大家是否发现代码存在问题或可以改进的地方呢? 首先,我们在客户端代码中,创建一个数据库连接,它需要占用一定的系统资源,当操作完毕之后我们需要释放占用的系统资源,当然,我们可以手动释放资源,具体实现如下: 假如,在释放SqlCommand资源时抛出异常,那么在它后面的资源SqlConnection将得不到释放。我们仔细想想当发生异常时,可以通过try/catch捕获异常,所以无论是否发生异常都可以使用finally检查资源是否已经释放了,具体实现如下: 通过上面的finally方式处理了异常情况是很普遍的,但为了更安全释放资源,使得我们增加了finally和if语句,那么是否有更简洁的方法实现资源的安全释放呢? 其实,我们可以使用using语句实现资源的释放,具体实现如下: using语句:定义一个范围,将在此范围之外释放一个或多个对象。 上面的代码使用了using语句实现资源的释放,那么是否所有对象都可以使用using语句实现释放呢? 只有类型实现了IDisposable接口并且重写Dispose()方法可以使用using语句实现资源释放,由于SqlConnection和SqlCommand实现了IDisposable接口,那么我们可以使用using语句实现资源释放和异常处理。 在客户端代码中,我们使用拼接SQL语句方式实现数据写入,由于SQL语句是动态执行的,所以恶意用户可以通过拼接SQL的方式实施SQL注入攻击。 对于SQL注入攻击,我们可以通过以下方式防御: &#;正则表达校验用户输入 &#;参数化存储过程 &#;参数化SQL语句 &#;添加数据库新架构 &#;LINQ to SQL 接下来,我们将通过参数化SQL语句防御SQL注入攻击,大家也可以使用其他的方法防御SQL注入攻击,具体实现代码如下: 上面通过参数化SQL语句和using语句对代码进行改进,现在代码的可读性更强了,而且也避免了SQL注入攻击和资源释放等问题。 接下来,让我们简单的测试一下代码执行时间,首先我们在代码中添加方法Stopwatch.StartNew()和Stopwatch.Stop()来计算写入代码的执行时间,具体代码如下: 上面,我们往数据库中写入了条数据,执行时间为 7.秒(我的机器很破了),这样系统性能还是可以满足许多公司的需求了。 假如,用户请求量增大了,我们还能保证系统能满足需求吗?事实上,我们不应该满足于现有的系统性能,因为我们知道代码的执行效率还有很大的提升空间。 接下来,将进一步介绍代码改善的方法。

图2 数据写入Users表 为了使数据库获得更快的写入速度,我们必须了解数据库在进行写入操作时的主要耗时。 数据库性能开销 连接时间 当我们执行conn.Open()时,首先,必须建立物理通道(例如套接字或命名管道),必须与服务器进行初次握手,必须分析连接字符串信息,必须由服务器对连接进行身份验证,必须运行检查以便在当前事务中登记,等等 这一系列操作可能需要一两秒钟时间,如果我们每次执行conn.Open()都有进行这一系列操作是很耗费时间的,为了使打开的连接成本最低,ADO.NET使用称为连接池的优化方法。 连接池:减少新连接需要打开的次数,只要用户在连接上调用 Open()方法,池进程就会检查池中是否有可用的连接,如果某个池连接可用,那么将该连接返回给调用者,而不是创建新连接;应用程序在该连接上调用 Close()或Dispose() 时,池进程会将连接返回到活动连接池集中,而不是真正关闭连接,连接返回到池中之后,即可在下一个 Open 调用中重复使用。 解析器的开销 当我们向SQL Server传递SQL语句INSERT INTO …时,它需要对SQL语句进行解析,由于SQL Server解析器执行速度很快,所以解析时间往往是可以忽略不计,但我们仍然可以通过使用存储过程,而不是直SQL语句来减少解析器的开销。 数据库连接 为了提供ACID(事务的四个特性),SQL Server必须确保所有的数据库更改是有序的。它是通过使用锁来确保该数据库插入、删除或更新操作之间不会相互冲突(关于数据库的锁请参考这里)。 由于,大多数数据库都是面向多用户的环境,当我们对User表进行插入操作时,也许有成千上百的用户也在对User表进行操作,所以说,SQL Server必须确保这些操作是有序进行的。 那么,当SQL Server正在做所有这些事情时,它会产生锁,以确保用户获得有意义的结果。SQL Server保证每条语句执行时,数据库是完全可预测的(例如:预测SQL执行方式)和管理锁都需要耗费一定的时间。 约束处理 在插入数据时,每个约束(如:外键、默认值、SQL CHECK等)需要额外的时间来检测数据是否符合约束;由于SQL Server为了保证每个插入、更新或删除的记录都符合约束条件,所以,我们需要考虑是否应该在数据量大的表中增加约束条件。 Varchar VARCHAR是数据库常用的类型,但它也可能导致意想不到的性能开销;每次我们存储可变长度的列,那么SQL Server必须做更多的内存管理;字符串可以很容易地消耗数百字节的内存的,如果我们在一个VARCHAR列中设置索引,那么SQL Server执行B-树搜索时,就需要进行O(字符串长度)次比较,然而,整数字段比较次数只受限于内存延迟和CPU频率。 磁盘IO SQL Server最终会将数据写入到磁盘中,首先,SQL Server把数据写入到事务日志中,当执行备份时,事务日志会合并到永久的数据库文件中;这一系列操作由后台完成,它不会影响到数据查询的速度,但每个事物都必须拥有属于自己的磁盘空间,所以我们可以通过给事务日志和主数据文件分配独立的磁盘空间减少IO开销,当然,最好解决办法是尽可能减少事务的数量。 正如大家所看到的,我们通过优化联接时间、 解析器的开销、 数据库联接、约束处理,、Varchar和磁盘IO等方法来优化数据库,接下来,我们将对前面的例子进行进一步的优化。 使用存储过程 前面例子中,我们把SQL代码直接Hardcode在客户端代码中,那么,数据库就需要使用解析器解析客户端中SQL语句,所以我们可以改用使用存储过程,从而,减少解析器的时间开销;更重要的一点是,由于SQL是动态执行的,所以我们修改存储过程中的SQL语句也无需重新编译和发布程序。 User表中的字段user_registered设置了默认值(GETDATE()),那么我们通过消除表默认值约束来提高系统的性能,简而言之,我们需要提供字段user_registered的值。 接下来,让我们省去User表中的默认值约束和增加存储过程,具体代码如下: 上面我们定义了存储过程SP_Insert_jk_users向表中插入数据,当我们重新执行代码时,发现数据插入的时间缩短为6.秒。

图3数据写入时间 使用数据库事务 想想数据是否可以延长写入到数据库中,是否可以批量地写入呢?如果允许延迟一段时间才写入到数据库中,那么我们可以使用Transaction来延迟数据写入。 数据库事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。 SQL Server确保事务执行成功后,数据写入到数据库中,反之,事务将回滚。 如果我们对数据库进行十次独立的操作,那么SQL Server就需要分配十次锁开销,但如果把这些操作都封装在一个事务中,那么SQL Server只需要分配一次锁开销。 图4 数据写入时间 使用SqlBulkCopy 通过使用事务封装了写入操作,当我们重新运行代码,发现数据写入的速度大大提高了,只需4.秒,由于一个事务只需分配一次锁资源,减少了分配锁和数据库联接的耗时。 当然,我们可以也使用SqlBulkCopy实现大量数据的写入操作,具体实现代码如下:

图5 数据写入时间 上面,我们通过事务和SqlBulkCopy实现数据批量写入数据库中,但事实上,每次我们调用cmd.ExecuteNonQuery()方法都会产生一个往返消息,从客户端应用程序到数据库中,所以我们想是否存在一种方法只发送一次消息就完成写入的操作呢? 使用表参数 如果,大家使用SQL Server ,它提供一个新的功能表变量(Table Parameters)可以将整个表数据汇集成一个参数传递给存储过程或SQL语句。它的注意性能开销是将数据汇集成参数(O(数据量))。 现在,我们修改之前的代码,在SQL Server中定义我们的表变量,具体定义如下: 上面,我们定义了一个表参数jk_users_bulk_insert,接着我们定义一个存储过程接受表参数jk_users_bulk_insert,具体定义如下: 接下我们在客户端代码中,调用存储过程并且将表作为参数方式传递给存储过程。 现在,我们重新执行写入操作发现写入效率与SqlBulkCopy相当。 1.1.3总结 本文通过博客系统用户表设计的例子,介绍我们在设计过程中容易犯的错误和代码的缺陷,例如:SQL注入、数据库资源释放等问题;进而使用一些常用的代码优化技巧对代码进行优化,并且通过分析数据库写入的性能开销(连接时间、解析器、数据库连接、约束处理、VARCHAR和磁盘IO),我们使用存储过程、数据库事务、SqlBulkCopy和表参数等方式降低数据库的开销。

[1]

sqlserver CONVERT()函数用法小结 CONVERT的使用方法:格式:CONVERT(data_type,expression[,style])说明:此样式一般在时间类型(datetime,smalldatetime)与字符串类型(nchar,nvarchar,char,varchar)相互转换的时候才

MSSQL数据附加失败报错解决办法 解决办法:1.新建一个同名的数据库(数据文件与原来的要一致)2.再停掉sqlserver(注意不要分离数据库)3.用原数据库的数据文件覆盖掉这个新建的数据库4.

编程经验点滴 动态SQL的拼接技巧 常见的误解有:1.只用ado.net,无法进行动态SQL拼接。2.有几个动态参数,代码的重复量就成了这些参数的不同数量的组合数,动态参数越多,重复量越

标签: sql server 性能调优

本文链接地址:https://www.jiuchutong.com/biancheng/348190.html 转载请保留说明!

上一篇:磁盘缓存专题之一 缓存命中和缓存未命中&缓存与缓冲间的差异(磁盘缓存技术)

下一篇:sqlserver CONVERT()函数用法小结

  • 第三方代付款的账务处理
  • 会计上已资本化处理的工资企业所得税前应如何扣除?
  • 企业所得税纳税人
  • 减免所得税额怎么做分录
  • 地税补缴社保
  • 已抵扣发票冲红会计分录
  • 应交税费和税金及附加的区别
  • 事业单位无形资产管理制度
  • 行政事业单位无偿调拨资产会计处理
  • 汇总记账凭证长什么样
  • 电商平台退货退款流程图
  • 行政单位维修工程规定
  • 刷信用卡付货款怎么操作
  • 工程设计企业符合增值税抵减政策吗
  • 划拨土地使用权多少年
  • 出口退税总是差进项票怎么处理
  • 虚开进项税额转出会计分录
  • 金三打印客户端插件如何下载?
  • 营改增后小规模纳税人转一般纳人
  • 增值税发票系统升级版
  • 购进货物不能抵扣进项税额
  • 车间日常维修费用计入什么科目
  • 不征税收入与免税收入的区别
  • ThinkPHP让../Public在模板不解析(直接输出)的方法 原创
  • 商场外面的广告牌叫什么
  • 重装系统前需要注意什么
  • 电力安装有前途吗
  • 失控发票的企业如何处理
  • 摊销租赁费属于什么费用
  • PHP:stream_get_line()的用法_Stream函数
  • php爬虫源码
  • ps工具栏失灵
  • 土地增值税属于财产税吗
  • 动态定位
  • 加班费的计算基数包括补贴吗
  • 店面装修费怎么算
  • vue0
  • php事件机制
  • 私募股权基金公司是做什么的
  • 对公账号备用金怎么用
  • 补发工资个人所得税税
  • 长期股权投资核算的成本法与权益法的主要差别有哪些
  • 织梦文章标题显示不全
  • 商业承兑汇票如何追索
  • 广告制作费属于广告服务吗
  • PostgreSQL教程(十八):客户端命令(2)
  • 以前年度损益调整结转到哪里
  • 除湿机计入固定费用吗
  • 应付职工薪酬的账务处理
  • 单位结算卡和对公账户号码不一样
  • 从厂家直接拿货需要什么条件
  • 新开企业如何开发票
  • 主营业务成本如何设置明细
  • 转租单位房子合法吗
  • 资产负债表本期没有发生额怎么填
  • 如何冲减费用做账
  • 票据的提示承兑期限是什么意思
  • ef使用sql语句
  • mysql数据库优化方案
  • 微软10月已停止服务中国用户
  • centos的优缺点
  • 简单易上手 固态硬盘SSD安装WIN7系统的3种办法
  • auepuf.exe是什么进程
  • linux命令行是什么字体
  • cpu numa
  • linux操作系统的安装步骤
  • 如何装win8.1
  • 事件委托机制的三个主要组件
  • 使用nodejs中httpProxy代理时候出现404异常的解决方法
  • django模块详解
  • perl 排序
  • 序列化和反序列化是什么意思
  • 在生成目录之前必须对相关文字设置样式
  • 浏览器窗口上线怎么办
  • shell脚本配置环境
  • jQuery leonaScroll 1.1 自定义滚动条插件(推荐)
  • jQuery simpleModal插件的使用介绍
  • 发票代码和发票号码有什么区别
  • 电子税务局辽宁省
  • 石油产品消费税征收
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设