1 概述
1.1 性能指标
数据库性能一般用两个方面的指标来衡量:响应时间和吞吐量。响应越快,吞吐量越大,数据库性能越好。响应时间和吞吐量有些情况下不能一起得到改善。
1.2 调优级别
对Sybase数据库性能调优,可以从四个方面进行:
一) 操作系统级:对网络性能、操作系统参数、硬件性能等作改进。
二) SQL Server级:调整存取方法,改善内存管理和锁管理等。
三) 数据库设计级:采用降范式设计,合理设计索引,分布存放数据等。
四) 应用程序级:采用高效SQL语句,合理安排事务,应用游标,处理锁。
本文对第一方面的内容不做讨论,第二方面提到的概念只适用于Sybase数据库,但第三、第四方面讨论的问题同样适用于Sybase外的其他数据库。以上各个方面的措施是相互牵连的,具体到解决一个性能问题,有时候要综合应用。
1.3 调优工具
在分析Sybase数据库的性能时,要用到一些数据库系统本身提供的性能调优工具,包括几个系统存储过程:
名称 |
功能简要介绍 |
sp_sysmon |
企业级系统性能报告工具 |
sp_lock |
查看锁的情况 |
sp_who |
查看线程的活动情况 |
sp_procqmode |
存储过程的查询处理模式 |
sp_configure |
配置SQL Server系统级参数 |
sp_estspace |
估计创建一个表需要的空间和时间 |
sp_spaceused |
估计表的总行数及表和索引占用的空间 |
sp_monitor |
监视CPU、I/O的统计活动情况 |
在利用isql等一些工具时,还可以设置查询会话中的几个选项,来显示SQL语句执行时的各种统计分析结果:
指令 |
On 的含义 |
set noexec on/off |
分析SQL语句后,还要执行 |
set statistics io on/off |
统计SQL执行所需I/O |
set statistics time on/off |
统计SQL语句执行耗时 |
set showplan on/off |
显示查询计划 |
1.4 sp_sysmon 的使用
企业级性能报告工具、系统存储过程sp_sysmon 的使用方法:
在isql 下,首先输入 sp_sysmon 'begin_sample' 启动一个报告采样
过一段时间后,再输入 sp_sysmon'end_sample' 结束上次报告采样
或者紧跟一参数 sp_sysmon 'end_sample',"dcache" 结束上次报告采样, 但只显示数据缓冲(Data CacheManagement)这一部分的情况。
能替换dcache的可选参数如下表所示:
参数 |
参数全称,内容范围解释 |
Dcache |
Data Cache Management,数据缓冲 |
Kernel |
Kernel Utilization,有关引擎、网络和I/O等情况 |
Wpm |
Worker Process Management |
Parallel |
Parallel Query Management |
Taskmgmt |
Task Management |
Appmgmt |
Application Management |
Esp |
ESP Management |
Housekeeper |
Housekeeper Task Activity |
Monaccess |
Monitor Access to Executing SQL |
Xactsum |
Transaction Profile |
Xactmgmt |
Transaction Management |
Indexmgmt |
Index Management,索引管理 |
Mdcache |
Metadata Cache Management |
Locks |
Lock Management,锁管理 |
Pcache |
Procedure Cache Management |
Memory |
Memory Management |
Recovery |
Recovery Management |
Diskio |
Disk I/O Management,磁盘I/O管理 |
Netio |
Network I/O Management |
1.5
用sp_sysmon可以得到数据库系统的性能基准报告,但要在比较稳定的状态下产生,方可作为参考和对照的依据。
1.6 理解存储方法
只有清楚数据库存储数据的底层细节,如数据页、索引页的物理结构,每一行的大小计算,不同类型列占用的宽度等等问题,才能对各种调优措施有个深入领会。关于这个问题,比较复杂和细致,请自行参阅有关书籍。
一般地,对于更改数据的操作,要尽量促进数据库进行直接更新( Direct Updates ),所以要遵守以下几条原则:
1)除非必要,避免使用允许null值的列和可变长度的列。
2)如果varchar 和varbinary 列填充得比较满,毫不犹豫转成 char 和binary 列。
对于建表时指定的页填充率(page fillfactor)参数,要权衡确定数值大小。一般:小值,适合于有许多随机插入的表,该表的数据经常被删除,又经常被增加;大值,适合于大多数的数据被增加到表末尾,如客票系统的售票存根和退票存根表。
2 SQL Server级的调优
2.1 管理共享内存
数据库性能优化的首要方面是最优管理内存。数据库占用的共享内存分成数据缓冲(data cache)、存储过程缓冲(Procedure cache)等几块。在isql 下使用 sp_configure 'cache' 可以看到存储过程缓冲所占百分比(procedure cache percent),整个数据缓冲大小(total datacache size) 等参数。
2.1.1 存储过程缓冲(Procedure cache)
存储过程缓冲保持以下对象的查询计划:
Procedures :存储过程
Triggers :触发器
Views :视图
Rules :规则
Defaults :缺省
Cursors :游标
存储过程不可重入,意即每个并发用户调用都会在内存中产生一个拷贝。
Procedure, triggers, and views 当它们被装载到procedure cache中时,被查询优化器优化,建立查询计划。如果存储过程在缓冲中,被调用时就不需要重新编译。如果procedure cache太小,存储过程就会经常被其他调入内存的存储过程冲洗掉,当再次被调用时,存储过程又被调入内存,再重新编译,用户请求因此不得不等待。最严重的情况,如果procedure cache不够,存储过程甚至都不能运行。所以在内存足够的情况下,procedurecache percent 参数尽可能大一些。
2.1.2 数据缓冲(Data Cache)
数据缓冲用来缓存数据页和索引页,是除去存储过程缓冲,系统其他占用的缓冲外的剩余内存空间。通过给服务器增加物理内存扩大数据缓冲,是最有效的方法。当然,如果不能加内存,就只能通过减少存储过程缓冲的比例等方法来扩大数据缓冲了。
通过 sp_configure "extent I/O buffers", 20(可调) 命令,在Data Cache中保留一些页专用于创建索引时使用,可以显著提高创建索引的性能。但要注意每开辟一个缓冲占用16K 字节的系统内存。
2.1.3 命名缓冲
通过如下的命令:
1> sp_helpcache
2> go
查看某客票数据库中命名缓冲,得到的结果如下:
Cache Name Config Size Run Size Overhead
------------------------------------- ---------- ----------
DS30_Tran_Log 20.00 Mb 20.00 Mb 2.05 Mb
Systemtable 20.00 Mb 20.00 Mb 2.05 Mb
default datacache 0.00 Mb 4462.86 Mb 464.97 Mb
left_base_center 16.00 Mb 16.00 Mb 1.57 Mb
price_cache 8.00 Mb 8.00 Mb 0.85 Mb
可以看出有4个命名缓冲,分别绑定客票系统的应用日志表、一些重要且常用的系统表、余票表、票价系列表,另外1个是缺省数据缓冲。这种配置还不是最合理,应该进一步把Systemtable这个命名缓冲细分成很多个,每一个单独存放一张系统表。
2.1.4 缓冲策略
缓冲策略是指把数据提前读入内存的机制,分预取策略(Prefetch Strategy,即大I/O策略)和取后马上丢弃策略(Fetch-and-Discard)、提示策略(Hints)等几种。
可以在三个级别上设置表数据的预取策略(Prefetch Strategy,即大I/O策略)于:对象级,会话级,查询级。如果三个级别上都有设置,它们发生作用的优先顺序是:对象级> 会话级 > 查询级。
对于如何在查询级利用指定的缓冲池,可以查看下面例子(使用4K缓冲池):
select au_fname,au_lname
from authers(prefetch 4)
where au_id in (A372020631, ..., A1887081515 )
go
DSS应用往往得益于大的I/O,应该放开large I/O strategy预取策略。
如果一个应用倾向于OLTP特征,用户能在会话级关掉Prefetch来提高性能。对于OLTP应用,关闭large I/O strategy预取策略。
对于所取到的页不会有重用的情况,放开fetch-and-discard策略。客票系统对存根数据进行统计的应用,如财收日结账,营销分析数据整理模块和综合查询等,都可以利用这一结论。
查看几个操作频繁且较大的表上的缓冲策略,用如下命令:
sp_cachestrategycenter,seat_area
sp_cachestrategycenter,sale_record0505
2.2 管理锁
2.2.1 页锁升级阀限
优化锁的重要考虑是设置页级锁升级升级成表级锁的阀限。要尽量避免页锁很快升级成表级锁。
在某客票数据库中,用sp_configure ‘lock’可以看到如下结果:
deadlock checking period 500 0 1000 1000
number of locks 5000 46875 200000 200000
page lock promotion HWM 200 0 10000 10000
page lock promotion LWM 200 0 200 200
page lock promotion PCT 100 0 90 90
可以看到页锁升级的阀限有三个:HWM(最高点) 为10000,LWM(最低点)为200,PCT为90。Sybase数据库内部根据PCT值按公式PCT*TAB_SZ/100得出计算阀限,如果计算阀限 < LWM, 锁升级发生在LWM值;如果计算阀限 < HWM,锁升级发生在HWM值。如果 LWM < 计算阀限 < HWM ,锁升级发生在PCT*TAB_SZ/100值。
锁升级阀限设置分对象级和服务器级两种。
针对对象级设置(数据库上的表或表上的索引),配置命令是:
sp_setpglockpromote{"database" | "table"}, objname, new_lwm,new_hwm, new_pct
针对服务器级设置,配置命令是:
sp_setpglockpromoteserver, NULL, new_lwm, new_hwm, new_pct。
如果要删除掉对象级上的页锁升级阀限,用:
sp_dropglockpromote{"database" | "table"}, objname
2.2.2 减少锁争夺的方法:
1)降范式设计数据库,创建冗余表。
2)把堆表(没有聚族索引的表)分区。
3)对于小表,使用fillfactor和max_rows_per_page来减少行密度,从而使各行数据分布到许多页(此方法适用于SQLServer 11版,对于11.9.2版以后的Sybase数据,有了行级锁,此方法必要性不大)。
2.3 管理临时库(tempdb)
管理临时库一个重要原则是要避免临时表跨多个设备,可以把tempdb从master设备中分离出来,放到一个单独的设备上去。这样可以减少存取系统表时对I/O资源的争夺。
用sp_dropsegment 存储过程从master设备中移除tempdb的default段和system段。
为了进一步提高tempdb的I/O速度,可以考虑把tempdb整个放在RAM 驱动器或固态存储设备上,存取速度是一般磁盘的1000倍。
一般情况下,tempdb会非常频繁地争夺和占用缺省数据缓冲,因为查询会话中有许多临时表要创建、计算和删除。所以推荐把tempdb绑定到它自己的命名缓冲,这样可以防止临时对象在内存中的活动冲洗掉缺省数据缓冲中的其他对象,利于在多个缓冲间展开I/O。在使用临时表的时候,还有一个原则:尽量缩小表规模和行的宽度,每一行只包括必要的列。例如在用select * into生成临时表时,如果只需要几个列的数值,就不要用这样的语句,而直接选取需要的列。
2.4 使用多引擎(MultipleNetwork Engines)
如果操作系统使用了多个CPU,那么用sp_configure 配置数据库的参数:在线引擎数(max online engines),可以扩展系统的网络I/O容量,分布网络I/O到各个引擎,从而提高性能,允许更多的用户连接。
在用户登录数据库时,总是先登录到引擎0,由引擎0在可用引擎队列中选择一个挂最少连接的引擎来传递socket描述符,从而重定向连接到那个引擎,由该引擎去处理跟此用户连接相关的所有网络活动。
对于多引擎SMP结构,SQL Server引入了自旋锁(spinlock)的一种数据结构,在多个引擎间共享。对于不同类型的任务,在哈希表上分配不同的自旋锁,有页锁自旋锁、表锁自旋锁和地址自旋锁。
自旋锁的配置:
sp_configure"page lock spinlock ratio", newval
sp_configure"table lock spinlock ratio", newval
sp_configure"address lock spinlock ratio", newval
增大数值,可以减少碰撞,提高并发操作度。但是每一个自旋锁结构要占用256字节的内存。
如果数据库发生1279错,可能原因:
1)不允许足够的锁,解决办法是用sp_configure 调大 number of locks 数值
2)在engine freelock 缓冲中没有足够的锁,解决办法是用sp_configure调大 max engine freelocks 数值。
如果数据库系统使用了4个引擎,那么每个引擎的自由锁缓冲中包含:each engine-specificfreelock cache 包含 5000 * .20 /4 = 250 个锁。
在平时,经常用sp_monitor和sp_sysmon监视CPU使用率,如果所有CPU的利用率高于85%,增加CPU,然后增大数据库的引擎数,可以改善性能。
2.5 设备使用的优化
把最常插入的表分区,放在多个设备上,这样可以创建多个页链,从而改善多个并发插入时的性能,因为每一个插入都要找到页链,页链有多个,就允许多个插入同时进行。这一点,尤其适用于客票系统的存根表和订票存根表(CG30_RRT),所带来的性能改善会非常明显。
物理I/O的代价远大于逻辑I/O,所以要尽量减少磁盘进行物理I/O的次数,尽量多进行内存中的逻辑I/O。使用statistics io工具和sp_sysmon,来观察磁盘I/O。可以配置使用大的I/O来减少物理I/O的次数,方法有三个:
1)用更多的磁盘;
2)表和索引分开到不同的磁盘;
3)增加一次I/O系统参数值的大小。
SQL Server总是为I/O请求建立一个磁盘检查的调度环,用sp_configure "I/Opolling process count"来提高数值,加长环,可以降低引擎的检查次数,提高吞吐量。但较小的值一般有助于减少响应时间。
对于可用的磁盘I/O控制块,要查看操作系统文档,用sp_configure "diski/o structures"配置,这个数值要尽可能高。
分离日志和数据,到不同的设备;给tempdb自己的设备;分离表和索引到不同的设备。这些方法都可以减少I/O。
4)数据库设备设置为异步写,在创建数据库设备时候带上 dsync = false 参数 。
2.6 对事务处理的调优
2.6.1 事务类型
事务处理无外乎三种:1,OLTP;2, DSS; 3, OLTP + DSS 的混合负载
OLTP(联机事务处理)的特点:
u 数据插入、修改和删除频繁。
u 经常操作的是单个记录。
u 当不适当设计时,倾向于碰撞和冲突。
DSS(决策支持系统)的特点:
u 数据修改不太频繁。
u 如果有插入和删除,是大批量的。
u 平时一般是只读操作。
u 表连接很常见。
u 有比较特别的查询。
OLTP + DSS 混合负载的特点权衡:
u 在性能方面要比较,是要吞吐量还是响应时间。
u 在锁方面要比较,是要并发性强呢还是要数据一致性强。
2.6.2 事务管理原则
一般的事务管理原则有:
1) 分解大的事务成多个小的事务。如客票数据的备份操作中,要删除过期数据,如果设计小事务做循环,便不会影响应用,完全可以做到任何时候备份和删除,不一定非得等服务器闲的时候做。
2) 避免在单个事务中更新或删除大量的数据行。比如客票系统的席位库数据清理,即使在服务器闲的时候做这种操作,也会锁定整个表,影响售票。
3) 尽量用可以接受的最低孤立级(isolation level),来提高并发度。如在余票查询等功能的应用中,使用这种孤立级,便可以最大程度地降低对售票的影响。
4) 提高事务吞吐量的措施包括:避免延迟更新;尽可能使用存储过程等等。
2.6.3 跟事务特征相关的数据库可调参数或特性
相对于OLTP应用,SQL Server有一些特性来满足要求。
1) 命名缓冲(Named cache)
对于命名缓冲,可以配置多个不同大小的内存池,来满足不同的应用需求。对于多个引擎的情况,命名缓冲还有一项重要的功能是降低自旋锁的内部争夺。
2) 日志I/O缓冲大小可配置
sp_logiosize ["default" | "size" |"all" ]
缺省值是4K,但如果4K内存池没有配置,SQLServer会使用2K大小的内存池
3) 堆表可分区,分布插入操作到各个设备
适用于频繁插入的表和有并发BCP倒入数据的表,如客票系统的售票存根和退票存根表。
4) 锁升级阀限可配置。
相对于DSS应用,SQL Server也有一些特性来满足要求
1) 应用大的 I/O 缓冲池
用sp_poolconfig来配置。
2) 绑定热表到命名缓冲
如 sysindexes, syslogs, 注意如果把 syslogs 放到单独的缓冲中,可以减少在缺省或其他命名缓冲上的自旋锁争夺。对于客票系统的train_dir, stop_time, 票价表, 取票存储过程相关的表都可以放在单独的命名缓冲上。
3) 取后丢弃缓冲策略 (Fetch-and-discard cachestrategy)
不会冲洗掉缓冲中的常用对象,可以减少MRU链的争夺,较少对OLTP事务的干扰。
对于收入统计应用,统计过往存根表中的数据,可以应用这一策略。
2.7 网络方面的调优
Sybase客户和服务器之建传递的是TDS包,缺省大小是512字节。对于要传输大批量数据的应用,如BCP、 文本/图像的取用、大结果集SQL语句,要用下面的配置命令配置大的TDS包大小。
sp_configure"default network packet size", nnn
sp_configure"maximum network packet size", nnn
对于isql 和bcp,可以在应用级指定TDS包的大小:isql -Usa -P –Annn,bcp -Usa -P –Annn。
注意在调大maximum network packet size的参数后,要增大additional network memory 参数,来适应 maximum network packetsize 的要求。
3 数据库设计级的调优
3.1 降范式设计
数据库的基础理论中,倡导使用规范化数据库设计方法,简称范式设计。用范式来设计数据库,可以减少数据冗余度,减少插入、更新和删除异常,也可以提高一般性能。
但是有时为了提高某些特定的性能,有意打破范式设计,为了达到最好的效果。但这种情况下,一定要注意数据完整性维护的问题。降范式设计这种方式一般可以提高检索速度,但略微降低数据修改性能。对于应用开发来说,有些情况下,降范式设计还能简化应用程序编码。
3.2 降范式设计的好处
降范式设计一般能带来如下好处:
ü 减少表连接的需要。
ü 减少外部键和索引。
ü 减少表的数量。
ü 聚合列可以预先计算。
3.3 降范式设计的方法:
ü 增加冗余列。
ü 增加导出列,从一个或多个表的几个列中导出另外一个列。
ü 收拢表,几个表合成一个表。
ü 复制表,即制作表的副本。
ü 劈开表,分垂直劈开和水平劈开两种。如客票系统中存根表就进行了水平劈开,每天一张表,这样就避免了庞大的整张存根表上数据操作的锁资源、I/O资源的争夺,也利于备份和传输。水平劈开可以考虑把表中不太活动的数据放置在一个表中,而把经常变动的数据放在另外一个表中。垂直劈开是把多个列分成几组,每一组列成一个表。
3.4 管理数据相关性
如何管理降范式设计所带来的数据相关性,有以下几点措施:
ü 每天晚上刷新只读表,如客票营销数据表。
ü 批处理,如存根的传输。
ü 应用逻辑中处理,要有很好的开发文档作说明,便于应用开发。
ü 用触发器来维护。如席位库和余票库的数据映射关系便是由触发器来维护的。
是否要采用降范式设计,必须根据具体应用综合考虑。这种设计理念往往紧密结合具体应用,和应用的相关度很高,所以要求数据库分析员对兼具业务分析员的角色。
3.5 适当创建索引
对于在表的哪些列上创建索引,是聚族索引还是非聚族索引,索引列的排列顺序,都要根据应用的需要,具体决定。下面例子,从更新数据语句中用到的锁的角度来决定创建索引:
update account
set bal = 0
where acct_num = 25
如果acct_num列有索引,使用IS锁(Intent Shared page lock);如果acct_num列没有索引,使用X(Exclusive table lock)。所以要尽量在更新语句的条件参数列上建立索引。
下面还会对索引的合理利用展开讨论,这些讨论也是针对如何创建索引的指导。
4 应用程序级的调优
4.1 有效使用索引
对于查询条件和索引的配合使用,对SQL语句性能有至关重要的影响。如下考察两种常见的情况:
1)如果查询条件中包括索引的第一个列,而且结果列都在索引列中,系统使用匹配索引定位,数个I/O便定位到索引的页级,从索引页中直接提取了结果,不需要使用数据页。
2)如果查询条件中不包括索引的第一个列,而且结果列都在索引列中,系统使用非匹配索引扫描,不扫描数据页,从索引页中直接提取结果。这种情况也不使用数据页。
4.2 创建高效率查询
4.2.1 搜索参数(SARGs)
查询语句中where条件中的参数叫搜索参数(SARGs,Search Arguments),可以充分利用索引的where 条件书写格式表示为 column operatorexpression ,一般 operator 是:=, >, <, >=, <=, is null 。
而如果 operator 是!=, !> ,便不能充分利用索引。
如果要充分利用索引,在 column 中不要包括函数和其他操作; expression 必须是常量或可以转化成常量。
查询优化器会认为,between 相当于 >= 和<=, like 'Ger%' 相当于 >='Ger' and < 'Ges'。但是 like '%ber' 因为没有给出首字母,就不能转化成这种结果
在书写sql语句时,对于表连接的情况,注意尽量多写冗余条件。下面三个样例查询,在搜索参数上略有差别:
查询1,
SELECT title, au_id
FROM titles t, titleauthor ta
WHERE t.title_id = ta.title_id
AND t.title_id='T81002'
查询2,
SELECT title, au_id
FROM titles t, titleauthor ta
WHERE t.title_id = ta.title_id
AND ta.title_id= 'T81002'
查询3,
SELECT title, au_id
FROM titles t, titleauthor ta
WHERE t.title_id = ta.title_id
AND t.title_id= 'T81002'
AND ta.title_id= 'T81002'
在这里,表titles和表titleauthor是一对多的关系,所以查询1比查询2高效,但查询3比查询1和查询2都要好,它让查询优化器根据两个表来充分调用潜在系统资源来满足SARGs。
4.2.2
一般要在SARGs的列上放置一个索引。
4.2.3 索引覆盖查询
如果被查询列都包括在索引列中,这种查询叫索引覆盖查询。这种查询效率比较高,要尽量使用这种查询。例:
在表 authors 上有非聚族索引 (au_lname, au_fname, au_id), 表中5000行数据
查询1,
select au_id from authors
where au_fname = 'Eliot' and au_lname ='Wilk' 3次读
查询2,
select au_fname, au_lname from authors
where au_id = 'A1714224678' 95次读
查询3,
select au_fname, au_lname, phone fromauthors
where au_id = 'A1714224678' 222次读
查询4,
select au_id, phone from authors
where au_fname = 'Eliot' and au_lname ='Wilk' 4次读
查询1,where 从句中列都在索引列中,索引包含了所有的查询信息,所以速度很快。
查询2,where 从句不包括索引列的首列,所以查询优化器扫描索引的整个叶级。
查询3,在选择列表中增加一个非覆盖列(索引列中不包含的列),引起表扫描。
查询4,虽然在选择列表中增加一个非覆盖列,但是where 从句包含索引列的首列,所以比查询1只增加一次读数据页的操作。
4.2.4 表连接查询的讲究
在做表连接查询时,在外表的连接列上建立索引,可以大大加快速度。
在做表连接查询时,表的排列顺序,也跟查询速度有关系。比如假设表 titles 和表 titleauthor 的数据统计情况:
表 |
行数 |
行宽度 |
数据页数 |
Titles |
5000 |
250 字节 |
620 |
Titleauthor |
2062 |
22 字节 |
68 |
查询1:
select t.title from titles t, titleauthor ta
where t.title_id = ta.title_id
and royaltyper > 50
在titleauthor.titleid有聚族索引,这种排列顺序是把titles作为外部表,查询优化器这样确定逻辑I/O的次数:外部表titles的页数+ (外部表titles的行数 * 2 )= 620 + (5000 * 2) =10,620 。
(注意从表titleauthor中取每一行估计有2次读,一次索引页,一次数据页)
查询2:
select t.title from titles t, titleauthor ta
where t.title_id = ta.title_id
and royaltyper > 50
在titles.titleid有聚族索引,这种排列顺序是把titleauthor 作为外部表,查询优化器这样确定逻辑I/O的次数:外部表titleauthor的页数 + (外部表titleauthor的行数 * 2 )= 68 + (2062 *2) = 4192。
可见,在表连接查询中,如果行数大的表放在后面位置可以提高速度。
4.2.5 孤立级0的妙用
当应用需要较好的并发性,并且近似的查询结果也可接受的情况下,SQL语句要用孤立级isolation level 0,尤其是对于有多个处理器环境下的OLTP应用。isolation level 0扫描不获取锁,所以不需要内部的重扫描,大大提高效率。
在客票系统的余票查询应用中,因为余票查询的结果是个动态而近似的参考数值,只对很短的一段时间内有效,供指导售票之用,不需要很精确,所以对于余票查询模块,包括综合查询中的子功能,计划管理中的子功能,尤其是前台售票中的子功能,如果用到此孤立级,可以很好地改善售票高峰期的所以售票程序长久没有反应,相互等待的现象。但须注意,isolation level 0忽略查询优化器,依赖唯一索引,所以要慎重创建SQL语句,最好由有丰富经验的程序员来完成。
如下是一些SQL语句用到isolation level 0的格式。
declare cs1 cursor for select ... at isolation {0 | readuncommitted }
select ... atisolation 0
readtext ... atisolation 0
4.2.6 存储过程的重编译
存储过程执行的时候带参数 with recompile, 可以让查询优化器更新查询计划。
当在表上增加索引,或者执行了 update statistics 指令后,运行 sp_recomplietable_name, 则所有依赖于此表的存储过程下次运行时被重新编译,即更新它们的查询计划。
如果存储过程中会创建临时表,它总是重新生成查询计划。
当表上被查询计划使用的索引或者对象被删除后,存储过程总是会自动重新编译
要注意如有必要,尽可能经常地编译存储过程,使存储过程的查询计划跟数据库的数据存放结构保持一致。
对于客票系统,每次备份删除数据,增加或重建索引后,要执行 update statistics 指令,然后运行 sp_recomplietable_name来更新相关存储过程的查询计划。
4.3 使用游标时的性能考虑
因为游标会引起页级和表级锁,且消耗网络资源,又有较多的处理指令,所有除非必要,尽量不用游标,而采用等价的SQL语句,即使SQL语句会涉及到多个表扫描,也会更好。
对于客票系统大量的存储过程,尤其是使用最频繁的取票,取车次等几个存储过程,要重点优化,减少游标的使用。