SQL Server数据库性能优化数据库教程

| 收藏本文 下载本文 作者:Philein

以下是小编精心整理的SQL Server数据库性能优化数据库教程(共含8篇),希望对大家有所帮助。同时,但愿您也能像本文投稿人“Philein”一样,积极向本站投稿分享好文章。

SQL Server数据库性能优化数据库教程

篇1:SQL Server数据库性能优化数据库教程

server|数据|数据库|性能|优化

设计1个应用系统似乎并不难,但是要想使系统达到最优化的性能并不是一件容易的事,

SQL Server数据库性能优化数据库教程

。在开发工具、数据库设计、应用程序的结构、查询设计、接口选择等方面有多种选择,这取决于特定的应用需求以及开发队伍的技能。本文以SQL Server为例,从后台数据库的角度讨论应用程序性能优化技巧,并且给出了一些有益的建议。

1 数据库设计

要在良好的SQL Server方案中实现最优的性能,最关键的是要有1个很好的数据库设计方案。在实际工作中,许多SQL Server方案往往是由于数据库设计得不好导致性能很差。所以,要实现良好的数据库设计就必须考虑这些问题。

1.1 逻辑库规范化问题

一般来说,逻辑数据库设计会满足规范化的前3级标准:

1.第1规范:没有重复的组或多值的列。

2.第2规范:每个非关键字段必须依赖于主关键字,不能依赖于1个组合式主关键字的某些组成部分。

3.第3规范:1个非关键字段不能依赖于另1个非关键字段。

遵守这些规则的设计会产生较少的列和更多的表,因而也就减少了数据冗余,也减少了用于存储数据的页。但表关系也许需要通过复杂的合并来处理,这样会降低系统的性能。某种程度上的非规范化可以改善系统的性能,非规范化过程可以根据性能方面不同的考虑用多种不同的方法进行,但以下方法经实践验证往往能提高性能。

1.如果规范化设计产生了许多4路或更多路合并关系,就可以考虑在数据库实体(表)中加入重复属性(列)。

2.常用的计算字段(如总计、最大值等)可以考虑存储到数据库实体中。

比如某一个项目的计划管理系统中有计划表,其字段为:项目编号、年初计划、二次计划、调整计划、补列计划…,而计划总数(年初计划+二次计划+调整计划+补列计划)是用户经常需要在查询和报表中用到的,在表的记录量很大时,有必要把计划总数作为1个独立的字段加入到表中。这里可以采用触发器以在客户端保持数据的一致性。

3.重新定义实体以减少外部属性数据或行数据的开支。相应的非规范化类型是:

(1)把1个实体(表)分割成2个表(把所有的属性分成2组)。这样就把频繁被访问的数据同较少被访问的数据分开了。这种方法要求在每个表中复制首要关键字。这样产生的设计有利于并行处理,并将产生列数较少的表。

(2)把1个实体(表)分割成2个表(把所有的行分成2组)。这种方法适用于那些将包含大量数据的实体(表)。在应用中常要保留历史记录,但是历史记录很少用到。因此可以把频繁被访问的数据同较少被访问的历史数据分开。而且如果数据行是作为子集被逻辑工作组(部门、销售分区、地理区域等)访问的,那么这种方法也是很有好处的。

1.2 生成物理数据库

要想正确选择基本物理实现策略,必须懂得数据库访问格式和硬件资源的操作特点,主要是内存和磁盘子系统I/O。这是一个范围广泛的话题,但以下的准则可能会有所帮助。

1.与每个表列相关的数据类型应该反映数据所需的最小存储空间,特别是对于被索引的列更是如此。比如能使用smallint类型就不要用integer类型,这样索引字段可以被更快地读取,而且可以在1个数据页上放置更多的数据行,因而也就减少了I/O操作。

2.把1个表放在某个物理设备上,再通过SQL Server段把它的不分簇索引放在1个不同的物理设备上,这样能提高性能。尤其是系统采用了多个智能型磁盘控制器和数据分离技术的情况下,这样做的好处更加明显。

3.用SQL Server段把一个频繁使用的大表分割开,并放在2个单独的智能型磁盘控制器的数据库设备上,这样也可以提高性能。因为有多个磁头在查找,所以数据分离也能提高性能。

4.用SQL Server段把文本或图像列的数据存放在1个单独的物理设备上可以提高性能。1个专用的智能型的控制器能进一步提高性能。

2 与SQL Server相关的硬件系统

与SQL Server有关的硬件设计包括系统处理器、内存、磁盘子系统和网络,这4个部分基本上构成了硬件平台,Windows NT和SQL Server运行于其上。

2.1 系统处理器(CPU)

根据自己的具体需要确定CPU结构的过程就是估计在硬件平台上占用CPU的工作量的过程。从以往的经验看,CPU配置最少应是1个80586/100处理器。如果只有2~3个用户,这就足够了,但如果打算支持更多的用户和关键应用,推荐采用Pentium Pro或PⅡ级CPU。

2.2 内存(RAM)

为SQL Server方案确定合适的内存设置对于实现良好的性能是至关重要的。SQL Server用内存做过程缓存、数据和索引项缓存、静态服务器开支和设置开支。SQL Server最多能利用2GB虚拟内存,这也是最大的设置值。还有一点必须考虑的是Windows NT和它的所有相关的服务也要占用内存。

Windows NT为每个WIN32应用程序提供了4GB的虚拟地址空间。这个虚拟地址空间由Windows NT虚拟内存管理器(VMM)映射到物理内存上,在某些硬件平台上可以达到4GB。SQL Server应用程序只知道虚拟地址,所以不能直接访问物理内存,这个访问是由VMM控制的。Windows NT允许产生超出可用的物理内存的虚拟地址空间,这样当给SQL Server分配的虚拟内存多于可用的物理内存时,会降低SQL Server的性能。

这些地址空间是专门为SQL Server系统设置的,所以如果在同一硬件平台上还有其它软件(如文件和打印共享,应用程序服务等)在运行,那么应该考虑到它们也占用一部分内存。一般来说硬件平台至少要配置32MB的内存,其中,Windows NT至少要占用16MB。1个简单的法则是,给每一个并发的用户增加100KB的内存。例如,如果有100个并发的用户,则至少需要32MB+100用户*100KB=42MB内存,实际的使用数量还需要根据运行的实际情况调整。可以说,提高内存是提高系统性能的最经济的途径。

2.3 磁盘子系统

设计1个好的磁盘I/O系统是实现良好的SQL Server方案的一个很重要的方面。这里讨论的磁盘子系统至少有1个磁盘控制设备和1个或多个硬盘单元,还有对磁盘设置和文件系统的考虑。智能型SCSI-2磁盘控制器或磁盘组控制器是不错的选择,其特点如下:

(1)控制器高速缓存。

(2)总线主板上有处理器,可以减少对系统CPU的中断。

(3)异步读写支持。

(4)32位RAID支持。

(5)快速SCSI―2驱动。

(6)超前读高速缓存(至少1个磁道)。

3 检索策略

在精心选择了硬件平台,又实现了1个良好的数据库方案,并且具备了用户需求和应用方面的知识后,现在应该设计查询和索引了。有2个方面对于在SQL Server上取得良好的查询和索引性能是十分重要的,第1是根据SQL Server优化器方面的知识生成查询和索引;第2是利用SQL Server的性能特点,加强数据访问操作,

3.1 SQL Server优化器

Microsoft SQL Server数据库内核用1个基于费用的查询优化器自动优化向SQL提交的数据查询操作。数据操作查询是指支持SQL关键字WHERE或HAVING的查询,如SELECT、DELETE和UPDATE。基于费用的查询优化器根据统计信息产生子句的费用估算。

了解优化器数据处理过程的简单方法是检测SHOWPLAN命令的输出结果。如果用基于字符的工具(例如isql),可以通过键入SHOW SHOWPLAN ON来得到SHOWPLAN命令的输出。如果使用图形化查询,比如SQL Enterprise Manager中的查询工具或isql/w,可以设定配置选项来提供这一信息。

SQL Server的优化通过3个阶段完成:查询分析、索引选择、合并选择。

1.查询分析

在查询分析阶段,SQL Server优化器查看每一个由正规查询树代表的子句,并判断它是否能被优化。SQL Server一般会尽量优化那些限制扫描的子句。例如,搜索和/或合并子句。但是不是所有合法的SQL语法都可以分成可优化的子句,如含有SQL不等关系符“”的子句。因为“”是1个排斥性的操作符,而不是1个包括性的操作符,所在扫描整个表之前无法确定子句的选择范围会有多大。当1个关系型查询中含有不可优化的子句时,执行计划用表扫描来访问查询的这个部分,对于查询树中可优化的SQL Server子句,则由优化器执行索引选择。

2.索引选择

对于每个可优化的子句,优化器都查看数据库系统表,以确定是否有相关的索引能用于访问数据。只有当索引中的列的1个前缀与查询子句中的列完全匹配时,这个索引才被认为是有用的。因为索引是根据列的顺序构造的,所以要求匹配是精确的匹配。对于分簇索引,原来的数据也是根据索引列顺序排序的。想用索引的次要列访问数据,就像想在电话本中查找所有姓为某个姓氏的条目一样,排序基本上没有什么用,因为你还是得查看每一行以确定它是否符合条件。如果1个子句有可用的索引,那么优化器就会为它确定选择性。

所以在设计过程中,要根据查询设计准则仔细检查所有的查询,以查询的优化特点为基础设计索引。

(1)比较窄的索引具有比较高的效率。对于比较窄的索引来说,每页上能存放较多的索引行,而且索引的级别也较少。所以,缓存中能放置更多的索引页,这样也减少了I/O操作。

(2)SQL Server优化器能分析大量的索引和合并可能性。所以与较少的宽索引相比,较多的窄索引能向优化器提供更多的选择。但是不要保留不必要的索引,因为它们将增加存储和维护的开支。对于复合索引、组合索引或多列索引,SQL Server优化器只保留最重要的列的分布统计信息,这样,索引的第1列应该有很大的选择性。

(3)表上的索引过多会影响UPDATE、INSERT和DELETE的性能,因为所有的索引都必须做相应的调整。另外,所有的分页操作都被记录在日志中,这也会增加I/O操作。

(4)对1个经常被更新的列建立索引,会严重影响性能。

(5)由于存储开支和I/O操作方面的原因,较小的自组索引比较大的索引性能更好一些。但它的缺点是要维护自组的列。

(6)尽量分析出每一个重要查询的使用频度,这样可以找出使用最多的索引,然后可以先对这些索引进行适当的优化。

(7)查询中的WHERE子句中的任何列都很可能是个索引列,因为优化器重点处理这个子句。

(8)对小于1个范围的小型表进行索引是不划算的,因为对于小表来说表扫描往往更快而且费用低。

(9)与“ORDER BY”或“GROUP BY”一起使用的列一般适于做分族索引。如果“ORDER BY”命令中用到的列上有分簇索引,那么就不会再生成1个工作表了,因为行已经排序了。“GROUP BY”命令则一定产生1个工作表。

(10)分簇索引不应该构造在经常变化的列上,因为这会引起整行的移动。在实现大型交易处理系统时,尤其要注意这一点,因为这些系统中数据往往是频繁变化的。

3.合并选择

当索引选择结束,并且所有的子句都有了一个基于它们的访问计划的处理费用时,优化器开始执行合并选择。合并选择被用来找出一个用于合并子句访问计划的有效顺序。为了做到这一点,优化器比较子句的不同排序,然后选出从物理磁盘I/O的角度看处理费用最低的合并计划。因为子句组合的数量会随着查询的复杂度极快地增长,SQL Server查询优化器使用树剪枝技术来尽量减少这些比较所带来的开支。当这个合并选择阶段结束时,SQL Server查询优化器已经生成了1个基于费用的查询执行计划,这个计划充分利用了可用的索引,并以最小的系统开支和良好的执行性能访问原来的数据。

3.2 高效的查询选择

从以上查询优化的3个阶段不难看出,设计出物理I/O和逻辑I/O最少的方案并掌握好处理器时间和I/O时间的平衡,是高效查询设计的主要目标。也就是说,希望设计出这样的查询:充分利用索引、磁盘读写最少、最高效地利用了内存和CPU资源。

以下建议是从SQL Server优化器的优化策略中总结出来的,对于设计高效的查询是很有帮助的。

1.如果有独特的索引,那么带有“=”操作符的WHERE子句性能最好,其次是封闭的区间(范围),再其次是开放的区间。

2.从数据库访问的角度看,含有不连续连接词(OR和IN)的WHERE子句一般来说性能不会太好。所以,优化器可能会采用R策略,这种策略会生成1个工作表,其中含有每个可能匹配的执行的标识符,优化器把这些行标志符(页号和行号)看做是指向1个表中匹配的行的“动态索引”。优化器只需扫描工作表,取出每一个行标志符,再从数据表中取得相应的行,所以R策略的代价是生成工作表。

3.包含NOT、、或! =的WHERE子句对于优化器的索引选择来说没有什么用处。因为这样的子句是排斥性的,而不是包括性的,所以在扫描整个原来数据表之前无法确定子句的选择性。

4.限制数据转换和串操作,优化器一般不会根据WHERE子句中的表达式和数据转换式生成索引选择。例如:

paycheck * 12>36000 or substring(lastname,1,1)=“L”

如果该表建立了针对paycheck和lastname的索引,就不能利用索引进行优化,可以改写上面的条件表达式为:

paycheck<36000/12 or lastname like “L%”

5.WHERE子句中的本地变量被认为是不被优化器知道和考虑的,例外的情况是定义为储备过程输入参数的变量。

6.如果没有包含合并子句的索引,那么优化器构造1个工作表以存放合并中最小的表中的行。然后再在这个表上构造1个分簇索引以完成一个高效的合并。这种作法的代价是工作表的生成和随后的分族索引的生成,这个过程叫REFORMATTING。 所以应该注意RAM中或磁盘上的数据库tempdb的大小(除了SELECT INTO语句)。另外,如果这些类型的操作是很常见的,那么把tempdb放在RAM中对于提高性能是很有好处的。

4 性能优化的其他考虑

上面列出了影响SQL Server的一些主要因素,实际上远不止这些。操作系统的影响也很大,在Windows NT下,文件系统的选择、网络协议、开启的服务、SQL Server的优先级等选项也不同程度上影响了SQL Server的性能。

影响性能的因素是如此的多,而应用又各不相同,找出1个通用的优化方案是不现实的,在系统开发和维护的过程中必须针对运行的情况,不断加以调整。事实上,绝大部分的优化和调整工作是在与客户端独立的服务器上进行的,因此也是现实可行的。

篇2:sqlserver 如何创建分区表数据库教程

server|sqlserver|创建

该文详细介绍实现分区表的过程以及有助于完成此过程的功能,

sqlserver 2005 如何创建分区表数据库教程

。逻辑流程如下:

图:创建分区表或索引的步骤

确定是否应为对象分区

虽然分区可以带来众多的好处,但也增加了实现对象的管理费用和复杂性,这可能是得不偿失的。尤其是,您可能不需要为较小的表或目前满足性能和维护要求的表分区。前面提到的销售方案使用分区减轻了移动行和数据的负担,但在决定是否实现分区时,您应考虑您的方案是否存在这种负担。

确定分区键和分区数

如果您正在尝试改善大型数据子集的性能和可管理性,并且已经定义了访问模式,则可以使用范围分区减少数据争用的情况,同时减少只读数据不需要分区时的维护工作。要确定分区数,应先评估您的数据中是否存在逻辑分组和模式。如果您通常一次只处理这些已定义子集中的少数几个,则应定义范围以隔离查询,使其只处理相应的数据(即,只处理特定的分区)。

确定是否应使用多个文件组

为了有助于优化性能和维护,应使用文件组分离数据。文件组的数目一定程度上由硬件资源决定:一般情况下,文件组数最好与分区数相同,并且这些文件组通常位于不同的磁盘上。但是,这主要适用于打算对整个数据集进行分析的系统。如果您有多个 CPU,SQL Server 则可以并行处理多个分区,从而大大缩短处理大量复杂报表和分析的总体时间。这种情况下,可以获得并行处理以及在分区表中移入和移出分区的好处。

创建文件组

如果需要为多个文件放置一个分区表以获得更好的 I/O平衡,则至少需要创建一个文件组。文件组可以由一个或多个文件构成,而每个分区必须映射到一个文件组。一个文件组可以由多个分区使用,但是为了更好地管理数据(例如,为了获得更精确的备份控制),应该对分区表进行设计,以便只有相关数据或逻辑分组的数据位于同一个文件组中。使用 ALTER DATABASE,可以添加逻辑文件组名,然后添加文件。要为 AdventureWorks 数据库创建名为 Q3 的文件组,请按以下方式使用 ALTER DATABASE:

ALTER DATABASE AdventureWorks ADD FILEGROUP [2003Q3]

创建文件组后,使用 ALTER DATABASE 将文件添加到该文件组中。

ALTER DATABASE AdventureWorks

ADD FILE

(NAME = N'2003Q3',

FILENAME = N'C:AdventureWorks2003Q3.ndf',

SIZE = 5MB,

MAXSIZE = 100MB,

FILEGROWTH = 5MB)

TO FILEGROUP [2003Q3]

通过在 CREATE TABLE 的 ON 子句中指定一个文件组,可以为文件创建一个表。但是,如果表未分区,则不能为多个文件组创建一个表。要为一个文件组创建表,请使用 CREATE TABLE 的 ON 子句。要创建分区表,必须先确定分区的功能机制。进行分区的标准以分区函数的形式从逻辑上与表相分离。此分区函数作为独立于表的定义存在,而这种物理分离将起到帮助作用,因为多个对象都可以使用该分区函数。因此,为表分区的第一步是创建分区函数。

为范围分区创建分区函数

范围分区必须使用边界条件进行定义。而且,即使通过 CHECK 约束对表进行了限制,也不能消除该范围任一边界的值。为了允许定期将数据移入该表,需要创建最后一个空分区。

在范围分区中,首先定义边界点:如果存在五个分区,则定义四个边界点值,并指定每个值是第一个分区的上边界 (LEFT) 还是第二个分区的下边界 (RIGHT)。根据 LEFT 或 RIGHT 指定,始终有一个空分区,因为该分区没有明确定义的边界点。

具体来讲,如果分区函数的第一个值(或边界条件)是 '1001',则边界分区中的值将是:

对于 LEFT

第一个分区是所有小于或等于 '20001001' 的数据

第二个分区是所有大于 '20001001' 的数据

对于 RIGHT

第一个分区是所有小于 '20001001' 的数据

第二个分区是所有大于或等于 '20001001' 数据

由于范围分区可能在 datetime 数据中进行定义,因此必须了解其含义。使用datetime具有某种含义:即总是同时指定日期和时间。未定义时间值的日期表示时间部分为“0”的 12:00 A.M。如果将 LEFT 与此类数据结合使用,则日期为 10 月 1 日 12:00 A.M. 的数据将位于第一个分区,而 10 月份的其他数据将位于第二个分区。从逻辑上讲,最好将开始值与 RIGHT 结合使用,而将结束值与 LEFT 结合使用。下面的三个子句将创建逻辑上相同的分区结构:

RANGE LEFT FOR VALUES ('20000930 23:59:59.997',

'20001231 23:59:59.997',

'0331 23:59:59.997',

'20010630 23:59:59.997')

RANGE RIGHT FOR VALUES ('20001001 00:00:00.000', '20010101 00:00:00.000', '20010401 00:00:00.000', '20010701 00:00:00.000')

RANGE RIGHT FOR VALUES ('20001001', '20010101', '20010401', '20010701')

注意:此处使用 datetime 数据类型确实增加了一定的复杂性,但您需要确保设置正确的边界情况。请注意使用 RIGHT 的简单性,因为默认时间为 12:00:00.000 A.M。对于 LEFT,复杂性增加是因为 datetime 数据类型具有精度。必须选择 23:59:59.997 的原因在于,datetime 数据无法保证毫秒级别的精度。相反,datetime 数据的精度在 3.33 毫秒内。使用 23:59:59.999 这个确切的时间值是不行的,因为该值将被舍入到最接近的时间值,即第二天的 12:00:00.000 A.M。由于进行了这种舍入,将无法正确定义边界,

对于 datetime 数据,必须对明确提供的毫秒值加倍小心。

注意:分区函数还允许将函数作为分区函数定义的一部分。您可以使用 DATEADD(ms,-3,'20010101'),而不是使用 '20001231 23:59:59.997' 明确定义时间。

要在四个活动分区(每个分区代表一个日历季度)中存储四分之一的 Orders 数据,并创建第五个分区以备将来使用(还是作为占位符,用于在分区表中移入和移出数据),请将 LEFT 分区函数与以下四个边界条件结合使用:

CREATE PARTITION FUNCTION OrderDateRangePFN(datetime)

AS

RANGE LEFT FOR VALUES ('20000930 23:59:59.997',

'20001231 23:59:59.997',

'20010331 23:59:59.997',

'20010630 23:59:59.997')

记住,定义四个边界点将创建五个分区。通过查看以下数据集检查此分区创建的数据集:

边界点 '20000930 23:59:59.997' 作为 LEFT(设置模式):

最左侧的分区将包含所有小于或等于 '20000930 23:59:59.997' 的值

边界点 '20001231 23:59:59.997':

第二个分区将包含所有大于 '20000930 23:59:59.997' 但小于或等于 '20001231 23:59:59.997' 的值

边界点 '20010331 23:59:59.997':

第三个分区将包含所有大于 '20001231 23:59:59.997' 但小于或等于 '20010331 23:59:59.997' 的值

边界点 '20010630 23:59:59.997':

第四个分区将包含所有大于 '20010331 23:59:59.997' 但小于或等于 '20010630 23:59:59.997' 的值

最后,第五个分区将包含所有大于 '20010630 23:59:59.997' 的值。

创建分区架构

创建分区函数后,必须将其与分区架构相关联,以便将分区定向至特定的文件组。定义分区架构时,即使多个分区位于同一个文件组中,也必须为每个分区指定一个文件组。对于前面创建的范围分区 (OrderDateRangePFN),存在五个分区;最后一个空分区将在 PRIMARY 文件组中创建。因为此分区永远不包含数据,所以不需要指定特殊的位置。

CREATE PARTITION SCHEME OrderDatePScheme

AS

PARTITION OrderDateRangePFN

TO ([2000Q3], [2000Q4], [2001Q1], [2001Q2], [PRIMARY])

注意:如果所有分区都位于同一个文件组中,则可以使用以下更简单的语法:

CREATE PARTITION SCHEME OrderDatePScheme

AS

PARTITION OrderDateRangePFN

ALL TO ([PRIMARY])

创建分区表

定义分区函数(逻辑结构)和分区架构(物理结构)后,即可创建表来利用它们。表定义应使用的架构,而架构又定义函数。要将这三者结合起来,必须指定应该应用分区函数的列。范围分区始终只映射到表中的一列,此列应与分区函数中定义的边界条件的数据类型相匹配。另外,如果表应明确限制数据集(而不是从负无穷大到正无穷大),则还应添加 CHECK 约束。

CREATE TABLE [dbo].[OrdersRange]

(

[PurchaseOrderID] [int] NOT NULL,

[EmployeeID] [int] NULL,

[VendorID] [int] NULL,

[TaxAmt] [money] NULL,

[Freight] [money] NULL,

[SubTotal] [money] NULL,

[Status] [tinyint] NOT NULL ,

[RevisionNumber] [tinyint] NULL ,

[ModifiedDate] [datetime] NULL ,

[ShipMethodID] [tinyint] NULL,

[ShipDate] [datetime] NOT NULL,

[OrderDate] [datetime] NOT NULL

CONSTRAINT OrdersRangeYear

CHECK ([OrderDate] >= '20030701'

AND [OrderDate] <= '0630 11:59:59.997'),

[TotalDue] [money] NULL

)

ON OrderDatePScheme (OrderDate)

GO

建立索引:是否分区?

默认情况下,分区表中创建的索引也使用相同的分区架构和分区列。如果属于这种情况,索引将与表对齐。尽管未作要求,但将表与其索引对齐可以使管理工作更容易进行,对于滑动窗口方案尤其如此。

例如,要创建唯一的索引,分区列必须是一个关键列;这将确保对相应的分区进行验证,以保证索引的唯一性。因此,如果需要在一列上对表进行分区,而必须在另一个列上创建唯一的索引,这些表和索引将无法对齐。在这种情况下,可以在唯一的列(如果是多列的唯一键,则可以是任一关键列)中对索引进行分区,或者根本就不进行分区。请注意,在分区表中移入和移出数据时,必须删除和创建此索引。

注意:如果您打算使用现有数据加载表并立即在其中添加索引,则通常可以通过以下方式获得更好的性能:先加载到未分区、未建立索引的表中,然后在加载数据后创建分区索引。通过为分区架构定义群集索引,可以在加载数据后更有效地为表分区。这也是为现有表分区的不错方法。要创建与未分区表相同的表并创建与已分区群集索引相同的群集索引,请用一个文件组目标位置替换创建表中的 ON 子句。然后,在加载数据之后为分区架构创建群集索引。

篇3:如何提高MySQL性能数据库教程

一、问题的提出

在应用系统开发初期,由于开发数据库数据比较少,对于查询SQL语句,复杂视图的的编写等体会不出SQL语句各种写法的性能优劣,但是如果将应用系统提交实际应用后,随着数据库中数据的增加,系统的响应速度就成为目前系统需要解决的最主要的问题之一,系统优化中一个很重要的方面就是SQL语句的优化。对于海量数据,劣质SQL语句和优质SQL语句之间的速度差别可以达到上百倍,可见对于一个系统不是简单地能实现其功能就可,而是要写出高质量的SQL语句,提高系统的可用性。

在多数情况下,Oracle使用索引来更快地遍历表,优化器主要根据定义的索引来提高性能。但是,如果在SQL语句的where子句中写的SQL代码不合理,就会造成优化器删去索引而使用全表扫描,一般就这种SQL语句就是所谓的劣质SQL语句。在编写SQL语句时我们应清楚优化器根据何种原则来删除索引,这有助于写出高性能的SQL语句。

二、SQL语句编写注意问题

下面就某些SQL语句的where子句编写中需要注意的问题作详细介绍。在这些where子句中,即使某些列存在索引,但是由于编写了劣质的SQL,系统在运行该SQL语句时也不能使用该索引,而同样使用全表扫描,这就造成了响应速度的极大降低。

1. IS NULL 与 IS NOT NULL

不能用null作索引,任何包含null值的列都将不会被包含在索引中。即使索引有多列这样的情况下,只要这些列中有一列含有null,该列就会从索引中排除。也就是说如果某列存在空值,即使对该列建索引也不会提高性能。

任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的。

2. 联接列

对于有联接的列,即使最后的联接值为一个静态值,优化器是不会使用索引的。我们一起来看一个例子,假定有一个职工表(employee),对于一个职工的姓和名分成两列存放(FIRST_NAME和LAST_NAME),现在要查询一个叫比尔.克林顿(Bill Cliton)的职工。

下面是一个采用联接查询的SQL语句,

select * from employss

where

first_name||''||last_name ='Beill Cliton'

上面这条语句完全可以查询出是否有Bill Cliton这个员工,但是这里需要注意,系统优化器对基于last_name创建的索引没有使用。

当采用下面这种SQL语句的编写,Oracle系统就可以采用基于last_name创建的索引。

Select * from employee

where

first_name ='Beill' and last_name ='Cliton'

遇到下面这种情况又如何处理呢?如果一个变量(name)中存放着Bill Cliton这个员工的姓名,对于这种情况我们又如何避免全程遍历,使用索引呢?可以使用一个函数,将变量name中的姓和名分开就可以了,但是有一点需要注意,这个函数是不能作用在索引列上。下面是SQL查询脚本:

select * from employee

where

first_name = SUBSTR('&&name',1,INSTR('&&name',' ')-1)

and

last_name = SUBSTR('&&name',INSTR('&&name’,' ')+1)

3. 带通配符(%)的like语句

同样以上面的例子来看这种情况。目前的需求是这样的,要求在职工表中查询名字中包含cliton的人。可以采用如下的查询SQL语句:

select * from employee where last_name like '%cliton%'

这里由于通配符(%)在搜寻词首出现,所以Oracle系统不使用last_name的索引,

在很多情况下可能无法避免这种情况,但是一定要心中有底,通配符如此使用会降低查询速度。然而当通配符出现在字符串其他位置时,优化器就能利用索引。在下面的查询中索引得到了使用:

select * from employee where last_name like 'c%'

4. Order by语句

ORDER BY语句决定了Oracle如何将返回的查询结果排序。Order by语句对要排序的列没有什么特别的限制,也可以将函数加入列中(象联接或者附加等)。任何在Order by语句的非索引项或者有计算表达式都将降低查询速度。

仔细检查order by语句以找出非索引项或者表达式,它们会降低性能。解决这个问题的办法就是重写order by语句以使用索引,也可以为所使用的列建立另外一个索引,同时应绝对避免在order by子句中使用表达式。

5. NOT

我们在查询时经常在where子句使用一些逻辑表达式,如大于、小于、等于以及不等于等等,也可以使用and(与)、or(或)以及not(非)。NOT可用来对任何逻辑运算符号取反。下面是一个NOT子句的例子:

... where not (status ='VALID')

如果要使用NOT,则应在取反的短语前面加上括号,并在短语前面加上NOT运算符。NOT运算符包含在另外一个逻辑运算符中,这就是不等于(;)运算符。换句话说,即使不在查询where子句中显式地加入NOT词,NOT仍在运算符中,见下例:

... where status ;'INVALID'

再看下面这个例子:

select * from employee where salary;3000;

对这个查询,可以改写为不使用NOT:

select * from employee where salary<3000 or salary>;3000;

虽然这两种查询的结果一样,但是第二种查询方案会比第一种查询方案更快些。第二种查询允许Oracle对salary列使用索引,而第一种查询则不能使用索引。

6. IN和EXISTS

有时候会将一列和一系列值相比较。最简单的办法就是在where子句中使用子查询。在where子句中可以使用两种格式的子查询。

第一种格式是使用IN操作符:

... where column in(select * from ... where ...);

第二种格式是使用EXIST操作符:

... where exists (select 'X' from ...where ...);

我相信绝大多数人会使用第一种格式,因为它比较容易编写,而实际上第二种格式要远比第一种格式的效率高。在Oracle中可以几乎将所有的IN操作符子查询改写为使用EXISTS的子查询。

第二种格式中,子查询以‘select 'X'开始。运用EXISTS子句不管子查询从表中抽取什么数据它只查看where子句。这样优化器就不必遍历整个表而仅根据索引就可完成工作(这里假定在where语句中使用的列存在索引)。相对于IN子句来说,EXISTS使用相连子查询,构造起来要比IN子查询困难一些。

通过使用EXIST,Oracle系统会首先检查主查询,然后运行子查询直到它找到第一个匹配项,这就节省了时间。Oracle系统在执行IN子查询时,首先执行子查询,并将获得的结果列表存放在在一个加了索引的临时表中。在执行子查询之前,系统先将主查询挂起,待子查询执行完毕,存放在临时表中以后再执行主查询。这也就是使用EXISTS比使用IN通常查询速度快的原因。

同时应尽可能使用NOT EXISTS来代替NOT IN,尽管二者都使用了NOT(不能使用索引而降低速度),NOT EXISTS要比NOT IN查询效率更高。

请作者联系本站,及时附注您的姓名。联系邮箱:edu#chinaz.com(把#改为@)。

篇4:Oracle Freelist和HWM原理探讨及相关性能优化数据库教程

oracle|性能|优化

Oracle Freelist和HWM原理探讨及相关性能优化

中兴通讯重庆研究所 游波

关键词:Freelist,HWM,存储参数,段,块,dump,优化

文章摘要:

近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些相关的讨论,本文以FreeList为线索对Oracle的存储管理的原理进行较深入的探讨,涉及Oracle段区块管理的原理,FreeList算法等。而与FreeList密切相关的一个重用特性HWM,与sql性能密切相关,本文也作了原理分析介绍。在原理探讨的基础上,介绍了常用的存储参数分析方法,并对所涉及的存储优化、HWM的优化和Freelist竞争优化作了说明。

缩略语:

ASSM:auto segement space management

HWM:high water mark

DBA:data block address

OLTP:online transaction process

OPS:oracle parallel server

1.简介

Oracle的空间管理和存储参数管理是Oracle管理及优化的重要部分。FreeList作为Oracle底层存储参数中的核心参数,其行为方式对Oracle的存储管理及性能优化有重大影响,而现有的Oracle文档对此方面的内容比较缺乏。虽然Oracle 9i已出现了ASSM,但是作为深入调优对FreeList认识仍是必要的。

近期来,FreeList的重要作用逐渐为Oracle DBA所认识,网上也出现一些相关的讨论。本文以FreeList为线索对Oracle的存储管理的原理进行较深入的探讨,涉及Oracle段区块管理的原理,FreeList算法等。而与FreeList密切相关的一个重用特性HWM,与sql性能密切相关,本文也作了原理分析介绍。在原理探讨的基础上,介绍了常用的存储参数分析方法,并对所涉及的存储优化、HWM的优化和Freelist竞争优化作了说明。

这些原理分析和性能优化都建立在探讨的基础上,限于篇幅和本人经验可能存在局限、偏差或谬误。

为了准确文中部分结构和字段的说明直接用英文描述。

限于篇幅本文不对同样很重要的block结构作更深入的讨论,对OPS性能有重要影响的free list group本文也未提及,因此本文在单一free list group下讨论。对于block的深入讨论、free list group的介绍与优化以及PCTUSED和PCTFREE等重要参数的优化请参见参考文献和资料。

2.原理探讨

FreeList作为一个Oracle存储管理的核心参数。其行为方式由Oralce内部控制,我们一般不需要掌握和控制。但是我们可能会遇到这些问题,当插入一条记录,会插入到那个块中?是使用新块,还是插入有数据的老块?段是什么时候扩展的,如何扩展的?表中只有一条记录,但是作一次select时代价却是上千个块,为什么?如果我们从原理上清楚了Oracle的存储管理方式,对相关这些问题的解决及性能优化就清晰自然了。

2.1 Oracle的逻辑储存结构

Oralce的逻辑存储结构按表空间,段,区,块进行管理。块是Oracle用来管理存储空间的最基本单元,Oracle数据库在进行输入输出操作时,都是以块为单位进行逻辑读写操作的。区由一系列连续的块组成,Oralce在进行空间分配、回收和管理时是以区为基本单位的。段由多个区组成,这些区可以是连续的也可以是不连续的,一般情况下一个对象拥有一个段。表空间中容纳段和区。

在生成段的时候,会同时分配初始区(initial extents), 初始区的第一个块就格式化为segment header,并被用来记录free list描述信息、extents信息,HWM信息等。

2.2 free list概念

free list是一种单向链表用于定位可以接收数据的块,在字典管理方式的表空间中,Oracle使用free list来管理未分配的存储块。Oracle记录了有空闲空间的块用于insert或Update。空闲空间来源于两种方式:1.段中所有超过HWM的块,这些块已经分配给段了,但是还未被使用。2.段中所有在HWM下的且链入了free list的块,可以被重用。free list具有下列属性

l        flag指示free list 被使用(1)或未使用(0)

l        free list 链的首块的地址DBA(data block address)

l        free list 链的尾块的地址DBA

free list 的信息通常保留在segment header中,这里给出segment header block dump片段加以说明:

nfl = 3, nfb = 1 typ = 1 nxf = 0

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

SEG LST:: flg: USED  lhd: 0x03c00233 ltl: 0x03c00233

SEG LST:: flg: USED  lhd: 0x03c00234 ltl: 0x03c00234

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

Segment Header:

==> nfl: number of free lists/block

==> nfb: number of free list blocks + segment header

==> typ: block type

==> nxf: number of transaction free lists

Segment List:

==> flg: flag USED or UNUSED the free list

==> lhd: head of free list

==> ltl: tail of free list

在每一个块中都有一个标记flg用来表明块是否链入了 free list链中。如果这个标志置上,该块中后向指针指向free list链中下一个块的DBA。如果当前块是链的最末尾的块,该后向指针值为0。

这里给出位于free list上的block dump的片段

Block header dump: 0x03c00235

Object id on Block? Y

seg/obj: 0xe2d8 csc: 0x00.6264c61 itc: 1 flg: O typ: 1 - DATA

fsl: 1 fnx: 0x3c00234 ver: 0x01

==> Seg/obj Object ID in dictionary

==> csc SCN of last block cleanout

==> itc Number of ITL slots

==> flg O = On freelist , - = Not on freelist

==> typ 1 = DATA  2 = INDEX

==> fsl ITL TX freelist slot

==> fnx DBA of NEXT block on freelist

举例来说如果有五个块在free list中,分别为A,B,C,D,E

就会形成segment header->A->B->C->D->E--|

同时segment header->E

2.3 free list类别

在段中存在3类free list, 即Master Freelists (MFL), Process Freelists (PrFL), 和 Transaction Freelists.

2.3.1 Master Free List(公用空闲空间池):

每一个段中有一个Master free list,在段创建的时候自动生成。对于每一个段来说都有这样一个空闲空间池,对每个进程都是公用的,空闲空间就是位于master free list 的块上。由于Master free list是公用的,因此当多个进程同时插入行到同一个段上,master free list竞争使用程度就会增加。

2.3.2 Process Free Lists

为了减少Master Free list的竞争问题, 引入了另一种free list叫做Process free lists, 根据sql命令 CREATE/ALTER 中的参数FREELISTS 创建. 这样多个free list 就可以分摊空闲空间的管理,以提高OLTP应用作高度并发插入和更新事务时空间分配管理的性能。通过指定CREATE TABLE / CLUSTER or INDEX的子句STORAGE的参数FREELISTS 来创建,例如: CREATE TABLE flg ( . . . .) . . . STORAGE ( ... FREELISTS 10 ...)。缺省的FREELISTS为1,此时不会创建Process free lists。当FREELISTS>=2时,创建Process free lists。

进程在使用process free list是根据进程的Oracle PID (Process ID)来选择的,公式如下:

select list entry = (PID % NFL) + 1

NFL : FREELISTS定义的Process free list个数

2.3.3 Transaction Free Lists

当Oracle需要时动态创建。一个Transaction Free List 是一种专门给某一个事务使用的free list. 每个段至少有16个transactions free lists, 并且这个值在需要时会增长,直到达到Segment Header块的大小限制。一个事务只有下面情况下会需要分配一个Tx Free Lists entry: 块中释放空间时(DELETE or UPDATE) 并且还不存在Tx Free Lists entry时。

2.4 Free list行为2.4.1 Freelist Link and Unlink 操作

Freelist 按后进先出队列(LIFO) 方式管理。也就是说最后被link到freelist的块拥有最先unlink的机会。

当块中空闲空间增加到大于PCTFREE时,块放入freelist中。free list中的块可用来作update 或insert。 当块中没有足够的空间用于insert操作时并且使用空间大于PCTUSED,块就会从free list中移出。

在块在DELETE or UPDATE 操作之后,如果使用空间落到PCTUSED下,块再次link到free list中。每次块加入free list时,都是link到链表的头部。

例如:考虑段中有120个块编号由1到120。其中有6个块在free list上并假设HWM是 80。(block实际使用DBA编号)

10->24->45->46->65->80-|

现在作INSERT 操作,需要400 bytes空间。假设块10上空间不足,但块24上空间可用。现在数据插入到块 24 ,现在块24的剩余空间小于该表的PCTUSED。因此块 24 从free list链表中移出。PCTFREE and PCTUSED参数的目的就是用来控制数据块从free list的链表中移入/移出行为的。现在free lists象这样:

10->45->46->65->80-|

然后在同一事务中作DELETE同一个段的数据,使块 54 和 67落到PCTUSED下。现在这些块加入到free list链中。free list链现在象这样:

67->54->10->45->46->65->80-|

2.4.2 Transaction Free List 算法

扫描segment Header块中所有的Tx free list,检查是否还没有Tx free list entry分配给transaction, 如何没有,将寻找未使用的entry或已经提交了事务的空的Tx free list。如果上述搜索过程失败, 新的entry会在segment Header块中Tx free lists区域中开辟。如果没有空间来生成, 事务就必须等待entry的释放。

segment header中的最大free list个数:

Block Size   Max # Freelists

-----------  -----------------

2K    24

4K    50

8K    101

16k    204

事务T1释放出来的空闲块(DELETE or UPDATE)的使用 :

l        立即被T1所重用

l        当T1 commit后被其它需要空闲块的事务重用,过程举例如下:

2.5 HMW概念

HIGH WATER MARK代表一个表使用的最大的(top limit)块 。2.1中已经提到HIGH WATER MARK 记录在segment header中,并且在Oracle插入数据时一般增长5个blocks(并非总是5个块,具体参见2.4.2中流程图中HMW增长方式)。

segment header block中与HWM相关信息说明如下:

EXTENT CONTROL:

Extent Header:: spare1: 0     space2: 0     #extents: 13    #blocks: 1429

last map 0x00000000 #maps: 0     offset: 4128

Highwater:: 0x04d0 ext#: 12    blk#: 275   ext size: 475

#blocks in seg. hdr's freelists: 5

#blocks below: 1229

mapblk 0x00000000 offset: 12

Unlocked

==> spare1:  this field is no longer used (old inc#, now always 0)

==> space2:  this field is no longer used (old ts#, now always 0)

==> #extents: number of extents allocated to segment

==> #blocks: number of blocks allocated to segment

==> last map: address of last extent map block

0 if extent map is entirely in the segment header

==> #maps:   number of extent map block

==> offset:  offset to end of extent map

==> HWM dba: address of block at highwater mark

==> ext#:    HWM extent number relative to segment

==> blk#:    HWM block number within extent

==> ext size: HWM extent size (in blocks)

==> #blocks in seg. hdr's freelists: number of blocks in seg. hdr's free list

==> #blocks below: number of blocks below HWM

==> mapblk dba: dba of extent map block containing HWM extent

is 0 if HWM is in the segment header

==> offset:  offset within extent map block

is the ext# if HWM is in segment header

==> Locked by: if locked by a transaction, the xid is displayed

HWM可以说是已经使用过的存储空间和未使用过的存储空间之间的分界线。在表使用过程中,HWM一直向一个方向移动,插入记录时HWM可能会向增加的方向移动,但是删除记录时HWM并不会向相反的方向移动。参见2.4.2。下图显示了某个数据段中HWM的位置情况。

图2.5

HIGH WATER MARK之所以重要是因为它对全表扫描性能的影响,

当实施一个全表扫描时,Oracle会读取所有HIGH WATER MARK下的块即使它们是空块。当HIGH WATER MARK 下有很多unused block时实施全表扫描会增加额外的不必要的I/O。它也会在全局共享区中填充很多很多空块。

3.分析方法

存储参数基本上属于oracle internal的东西,因此oralce并没有提供很好的手段来分析。但是对于DBA来说,还是可以通过block dump和DBMS_SPACE等手段来获取部分信息。

3.1 提取block和free list信息

创建dbms_space使用的存储过程show_space

SQL>

create or replace procedure show_space

( p_segname in varchar2,

p_owner in varchar2 default user,

p_type in varchar2 default 'TABLE',

p_partition in varchar2 default NULL )

as

l_free_blks number;

l_total_blocks number;

l_total_bytes number;

l_unused_blocks number;

l_unused_bytes number;

l_LastUsedExtFileId number;

l_LastUsedExtBlockId number;

l_last_used_block number;

procedure p( p_label in varchar2, p_num in number )

is

begin

dbms_output.put_line( rpad(p_label,40,'.') || p_num );

end;

begin

dbms_space.free_blocks

( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

partition_name => p_partition,

freelist_group_id => 0,

free_blks => l_free_blks );

dbms_space.unused_space

( segment_owner => p_owner,

segment_name => p_segname,

segment_type => p_type,

partition_name => p_partition,

total_blocks => l_total_blocks,

total_bytes => l_total_bytes,

unused_blocks => l_unused_blocks,

unused_bytes => l_unused_bytes,

last_used_extent_file_id => l_LastUsedExtFileId,

last_used_extent_block_id => l_LastUsedExtBlockId,

last_used_block => l_last_used_block );

p( 'Free Blocks', l_free_blks );

p( 'Total Blocks', l_total_blocks );

p( 'Total Bytes', l_total_bytes );

p( 'Unused Blocks', l_unused_blocks );

p( 'Unused Bytes', l_unused_bytes );

p( 'Last Used Ext FileId', l_LastUsedExtFileId );

p( 'Last Used Ext BlockId', l_LastUsedExtBlockId );

p( 'Last Used Block', l_last_used_block );

end;

过程已创建。

SQL> create table t1(a char(1000)) storage( freelists 3);

表已创建。

SQL> set serveroutput on;

SQL> exec show_space('T1');

Free Blocks.............................0      <==Number of blocks on freelist

Total Blocks............................5      <==Total data blocks in segment

Total Bytes.............................20480  <==Total bytes in segment

Unused Blocks...........................4      <==Total unused blocks in segment

Unused Bytes............................16384  <==Total unused bytes in segment

Last Used Ext FileId....................15     <==File id of last used extent

Last Used Ext BlockId...................562    <==Block id of last used extent

Last Used Block.........................1      <==Last used block in extent

PL/SQL 过程已成功完成。

有关show_space的进一步使用技巧可参考文献5。以下利用上面得到的数据对segment header block进行dump。

SQL>alter system dump datafile 15 block 562;

在udump/ora10792.trc中

*** -09-08 15:29:57.343

Start dump data blocks tsn: 27 file#: 15 minblk 562 maxblk 562

buffer tsn: 27 rdba: 0x03c00232 (15/562)

scn: 0x0000.064560e4 seq: 0x02 flg: 0x00 tail: 0x60e41002

frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED

Extent Control Header

-----------------------------------------------------------------

Extent Header:: spare1: 0     space2: 0     #extents: 1     #blocks: 4

last map 0x00000000 #maps: 0     offset: 2080

Highwater:: 0x03c00233 ext#: 0     blk#: 0     ext size: 4

#blocks in seg. hdr's freelists: 0

#blocks below: 0

mapblk 0x00000000 offset: 0

Unlocked

Map Header:: next 0x00000000 #extents: 1   obj#: 60033 flag: 0x40000000

Extent Map

-----------------------------------------------------------------

0x03c00233 length: 4

nfl = 3, nfb = 1 typ = 1 nxf = 0

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000

End dump data blocks tsn: 27 file#: 15 minblk 562 maxblk 562

对于上述块中字段的说明,以及相关试验。由于篇幅所限,本文不再列举。可参考文献7。

对非segment header的data block的dump方法和上述类似。data block的结构和segment header block不一样,如果需要了解,可查阅参考文献和资料。

3.2 提取HWM信息3.2.1 HWM位置

HWM位置按下面的公式计算:

HWM = useed byte = Total Bytes - Unused Blocks

Total Bytes和Unused Blocks都可以用show_space提取。

还可以通过ANALYZE tables得到HWM信息. DBA_TABLES视图中包含了可用于各表空间分析的列。其中blocks代表已使用过的块即HWM,empty_blocks代表未使用的空间。

3.2.1 HWM下空间利用信息

要比较有数据行的块的块数和HIGH WATER MARK下总块数,可以用下面的公式来展示HWM下未用空间的比例。

p = 1- r/h

r:有数据行的块的块数

h:HWM下的块数.

r可以通过如下方法获得:

Oracle7:

SELECT count(distinct substr(rowid, 15,4) || substr(rowid, 1,8) ) FROM schema.table;

Oracle8 and Oracle9:

SELECT count(distinct substr(rowid, 7,3) || substr(rowid, 10,6) ) FROM schema.table;

如果公式计算的结果 p是0,就不需要对表进行重建。如果结果p大于0,应该考虑系统状况和应用需要来决定是否需要总组表。

4.优化4.1手工回收存储空间

在HIGH WATER MARK以上的块对性能没有影响,但是会耗费空间。如何空间大小是一个考虑的问题,就可以决定回收空块。

假设表T1的存储示意图如图2.5所示,使用ALTER TABLE ... DEALLOCATE UNUSED语句可以回收HWM以上的空间。比如:

alter table t1 deallocate unused;

回收后T1的存储示意如图4.1.1

图4.1.1

如果在ALTER TABLE ... DEALLOCATE UNUSED语句中使用了KEEP关键字,则可以在HWM之后保留指定大小的空闲空间,比如:

alter table t1 deallocate unused keep 10K;

回收后T1的存储示意如图4.1.2

图4.1.2

4.2删减表

根据3.2.1可以得到HWM以下块的使用情况。如何p大于时,对全表扫描性能会产生影响,同时也会耗用空间。

如果能够确认应用有良好的索引几乎不会用到全表扫描,那么HIGH WATER MARK以下的空块,尽管耗费了空间,不会对访问产生影响。如果不能确定,那么就需要考虑删减表。

删减表的操作将删除表中所有的记录,并且重置HWM标记。表在删减之后将成为一个空表。

在Oracle中删减表只有如下的两种办法:

1.使用drop语句

先使用drop语句删除整个表,然后再重建这个表。在删除-重建的过程中,与表相关的所有索引、完整性约束以及触发器都会丢失,并且所有依赖于该表的对象都会变为INVALID状态,同时原来争对表的授权也会失效。因此采用这种方式删除表中的记录代价太大。

2.使用TRUNCATE语句

TRUNCATE语句属于DDL语句,不会产生任何回退信息,并且被立即自动提交。在执行TRUNCATE语句时不会影响到与被删减表相关的任何数据库对象与授权,也不会触发表中所定义的触发器。此外,在对标进行删减时,HWM将重置,已经为表分配的存储空间将被回收。

在执行TRUNCATE语句时,可以通过drop storage子句和reuse storage子句来控制被释放的区是否回收到表空间中。如何作在线系统的TRUNCATE,不希望表长时间锁住,那么可以使用reuse storage子句,仅将HWM重置。

4.3 free list优化

free list 竞争出现在多个进程使用同一个free list并试图同时修改free list头部数据块时。可以通过查询视图v$waitsate的class类型为data block 的记录来检查竞争情况。

产生data block类型竞争的主要原因是多个进程试图同时修改free list头部数据块。 然而,它也会出现在当进程准备将块读入buffer cathe时,另一个进程需要访问同一个块。如果能在V$SESSION_WAIT中正好捕获buffer busy waits,就可以通过查询V$SESSION_WAIT中的P3来判定是那一类。A 0 或 1014代表读类型,其他的值为修改竞争的类型。

下一步需要确定竞争涉及那些段。 如果能够在V$SESSION_WAIT捕获waits,就可以用P1和P2的值 (对应file 和 block) 在DBA_EXTENTS中找到段名。 如何是一个表,就很可能需要重建表来创建更多的process freelists。 一种计算需要创建多少个freelist的方法是dump一些段中接近HWM的块,检查interested transaction list的个数,具体方法可参见3.1。interested transactions个数的峰值加1 就是需要的最小process freelists的值。

从2.3和2.4可以看出,使用多个free list可能导致更多的空块未被使用, 也可能导致段更快地扩展。如果性能是当前所关心的重点,那么多free lists 可以用来提高并发访问能力,当然会增加一些额外空间的耗用。然而,如果空间使用大小是首先考虑的因素,那么推荐使用single freelist,使参数FREELISTS=1, 当然就不能提升并发事务的性能了。

V$WAITSTAT 也可显示其他类型class的竞争,包括segment header 和free list。 出现在同一个free list group中多个事务需要同时更新它们的free list header记录时。 有多种方法来解决这个问题如重建表采用更多的free list groups,或者增加 _bump_highwater_mark_count大小,或者调整应用本身。

参考文献和资料:

1.《FREELISTS and FREELIST GROUPS. SCOPE & APPLICATION 》

2.《INITRANS, MAXTRANS, FREELISTS and FREELIST GROUPS, PCTFREE and PCTUSED》,Mike Ault

3.《Freelist Internals: An OverviewKnowledge》,Xpert for Oracle Administration

4.《Blockdump - 8.x Data Segment Header in Oracle》

5.《AskTom dbms_space_free_space》,asktom.oracle.com

6.《Data Blocks and Freelists》,www.ixora.com.au

7.《偷窥Data block 的物理结构》,www.itpub.net

8.《Oracle 9i for windows nt/2000数据系统培训教程》,清华大学出版社

上述部分文章在我的blog网站blog.csdn.net/youbo2004上可找到,对于研究free list,free list group和block等有很好的帮助。

篇5:全面优化ADO数据库教程

ado|优化

1 Connection

1.1 Pooling

在Web Application中,常常会出现同时有很多用户同时访问数据库的情况,而且ASP中的对象作用域是页面级的,也就是

说,每个页面都要联接和断开数据库,岂不是会很慢?而且每个到SQL Server数据库的联接会带来37k的系统开销,怎么

办?

可能有人会想到用Application和Session来解决问题,但是,这是不可取的,如果用Application,那么会出现多个用户同时通过一个Connection访问数据库的情况,虽然节省了建立连接的时间,但是访问数据库的速度就会变得非常慢,如果用Session,出现的问题就是,Session超时怎么办?如果把Session.Timeout设得很大,那用户离开之后,连接还会保留一段时间,也会带来额外的开销。

其实根本不用考虑这个问题,通过OLE DB访问数据库,它会替你解决这个问题,OLE DB有一个Resource Pooling,它会代

理你的连接请求,然后把别人刚用过的连接给你接着用。(具体机制不再阐述,其实我也没搞太明白,嘻嘻)

1.2 Provider

可能没有多少人用过这个Property吧,它的缺省值是MSDASQL,还有MSIDXS和ADSDSOObject,但是在ADO2.0(见VS98)和

ADO2.1(见SQL7)里面提供了一些新的Provider:

MSDAORA (OLE DB Provider for Oracle)

Microsoft.Jet.OLEDB.3.51(OLE DB Provider for Microsoft Jet( for ACCESS))

SQLOLEDB(Microsoft SQL Server OLE DB Provider)

如果你所用的数据库是这些的话,用这些新的Provider就可以不通过ODBC而直接访问数据库,提高的效率就可想而知了。

2 Command

2.1 CommandType

缺省值是adCmdUnknown,ADO会逐个判断你的CommandType,直到它认为合适为止,不建议采用。(在Recordset.Open和

Connection.Execute的时候也可以用)

adCmdText是照原样执行你的SQL语句,但是如果你的SQL Language是以下几种的话,通过使用别的CommandType就可以提高

你的SQL语句执行效率

objCmd.Execute “Select * from table_name”, adCmdText可替换为objCmd.Execute “table_name”,adCmdTable

objCmd.Execute “Exec proceuure_name”,adCmdText可替换为objCmd.Execute “proceuure _name”, adCmdStoredProc

还有很重要的一点就是,如果你的SQL语句没有返回记录集,如insert和update等,那么使用adExecuteNoRecords

(ADO2.0)可以减低系统开销(可以加到adCmdText 和adCmdStoredProc上,如adCmdStoredProc + adExecuteNoRecords)

还有adCmdTableDirect和adCmdFile(ADO2.0),我还不太清楚怎么用,adCmdFile可用于访问一个XML文件,

2.2 Prepared

如果你需要重复的执行类似的SQL语句,那么你可以预编译你的SQL语句,提高的效率也很可观

objCmd.CommandText = “SELECT spell from TYPER.wordspell where word = ? ”

objCmd.Prepared = True

objCmd.Parameters.Append objCmd.CreateParameter(“word”, adVarChar, , 2)

For i = 1 To Len(strName)

strChar = Mid(strName, i, 1)

objCmd(“word”) = strChar

Set bjRS = objCmd.Execute

If objRS.EOF Then

strNamesame = strNamesame & strChar

Else

strNamesame = strNamesame & objRS(“spell”)

End If

Next ''i = 1 To Len(strName)

3 Recordset

3.1 LockType

缺省是adLockReadOnly,如果你不用修改数据,就不要改成adLockOptimistic之类的,否则也会减低速度和增加开销的

adLockReadOnly > adLockPessimistic > adLockOptimistic > adLockBatchOptimistic

3.2 CursorType

缺省是adOpenForwardOnly,如果你只用MoveNext Method,也最好不要改,速度影响140%左右

adOpenForwardOnly > adOpenDynamic > adOpenKeyset > adOpenStatic

3.3 CursorLocation

缺省是adUseServer,其实不好,它可以随时反映数据库服务器上的改动,但是系统开销很大,而且需要维持和数据库服务

器的连接,但是在数据库服务器和Web Server在一起的时候要快些。不过在adLockOptimistic的时候使我无法使用

RecordCount等Property。

使用用adUseClient的话,你可以对数据做再排序,筛选,shape等操作

如果对数据的实时性没有要求的话,尽量用adUseClient

4 其它

4.1 Early bind

用ASP这一点就不用看了,如果用VB的话

Dim objConn As ADODB.Connection 比 Set bjConn = CreateObject(“ADODB.Connection”)要好

4.2 ADO 2.1里的shape真是好玩

4.3 ADO 2.1可以用objRS.Fields.Append来建立一个Recordset

4.4 把Recordset的一列数据直接变成一个数组来操作速度快一些,但是系统开销要大一些

篇6:影响SQLserver性能的关键三个方面数据库

1 逻辑 数据库 和表的设计 数据库的逻辑设计、包括表与表之间的关系是优化关系型数据库 性能 的核心,一个好的逻辑数据库设计可以为优化数据库和应用程序打下良好的基

1 逻辑数据库和表的设计

数据库的逻辑设计、包括表与表之间的关系是优化关系型数据库性能的核心。一个好的逻辑数据库设计可以为优化数据库和应用程序打下良好的基础。

标准化的数据库逻辑设计包括用多的、有相互关系的窄表来代替很多列的长数据表。下面是一些使用标准化

表的一些好处。

A:由于表窄,因此可以使排序和建立索引更为迅速

B:由于多表,所以多镞的索引成为可能

C:更窄更紧凑的索引

D:每个表中可以有少一些的索引,因此可以提高insert update delete等的速度,因为这些操作在索引

多的情况下会对系统性能产生很大的影响

E:更少的空值和更少的多余值,增加了数据库的紧凑性

由于标准化,所以会增加了在获取数据时引用表的数目和其间的连接关系的复杂性。太多的表和复杂的连接关系会降低服务器的性能,因此在这两者之间需要综合考虑。

定义具有相关关系的主键和外来键时应该注意的事项主要是:用于连接多表的主键和参考的键要有相同的数据类型。

2 索引的设计

A:尽量避免表扫描

检查你的查询语句的where子句,因为这是优化器重要关注的地方。包含在where里面的每一列(column)都是可能的侯选索引,为能达到最优的性能,考虑在下面给出的例子:对于在where子句中给出了column1这个列。

下面的两个条件可以提高索引的优化查询性能!

第一:在表中的column1列上有一个单索引

第二:在表中有多索引,但是column1是第一个索引的列

避免定义多索引而column1是第二个或后面的索引,这样的索引不能优化服务器性能

例如:下面的例子用了pubs数据库。

SELECT au_id, au_lname, au_fname FROM authors

WHERE au_lname = 'White'

按下面几个列上建立的索引将会是对优化器有用的索引

?au_lname

?au_lname, au_fname

而在下面几个列上建立的索引将不会对优化器起到好的作用

?au_address

?au_fname, au_lname

考虑使用窄的索引在一个或两个列上,窄索引比多索引和复合索引更能有效。用窄的索引,在每一页上

将会有更多的行和更少的索引级别(相对与多索引和复合索引而言),这将推进系统性能。

对于多列索引,SQL Server维持一个在所有列的索引上的密度统计(用于联合)和在第一个索引上的

histogram(柱状图)统计。根据统计结果,如果在复合索引上的第一个索引很少被选择使用,那么优化器对很多查询请求将不会使用索引。

有用的索引会提高select语句的性能,包括insert,uodate,delete。

但是,由于改变一个表的内容,将会影响索引。每一个insert,update,delete语句将会使性能下降一些。实验表明,不要在一个单表上用大量的索引,不要在共享的列上(指在多表中用了参考约束)使用重叠的索引。

在某一列上检查唯一的数据的个数,比较它与表中数据的行数做一个比较。这就是数据的选择性,这比较结果将会帮助你决定是否将某一列作为侯选的索引列,如果需要,建哪一种索引。你可以用下面的查询语句返回某一列的不同值的数目。

select count(distinct cloumn_name) from table_name

假设column_name是一个10000行的表,则看column_name返回值来决定是否应该使用,及应该使用什么索引。

Unique values Index

5000 Nonclustered index

20 Clustered index

3 No index

镞索引和非镞索引的选择

<1:>镞索引是行的物理顺序和索引的顺序是一致的,

页级,低层等索引的各个级别上都包含实际的数据页。一个表只能是有一个镞索引。由于update,delete语句要求相对多一些的读操作,因此镞索引常常能加速这样的操作。在至少有一个索引的表中,你应该有一个镞索引。

在下面的几个情况下,你可以考虑用镞索引:

例如: 某列包括的不同值的个数是有限的(但是不是极少的)

顾客表的州名列有50个左右的不同州名的缩写值,可以使用镞索引。

例如: 对返回一定范围内值的列可以使用镞索引,比如用between,>,>=,<,<=等等来对列进行操作的列上。

select * from sales where ord_date between '5/1/93' and '6/1/93'

例如: 对查询时返回大量结果的列可以使用镞索引。

SELECT * FROM phonebook WHERE last_name = 'Smith'

当有大量的行正在 入表中时,要避免在本表一个自然增长(例如,identity列)的列上建立镞索引。如果你建立了镞的索引,那么insert的性能就会大大降低。因为每一个插入的行必须到表的最后,表的最后一个数据页。

当一个数据正在 入(这时这个数据页是被锁定的),所有的其他插入行必须等待直到当前的插入已经结束。

一个索引的叶级页中包括实际的数据页,并且在硬盘上的数据页的次序是跟镞索引的逻辑次序一样的。

<2:>一个非镞的索引就是行的物理次序与索引的次序是不同的。一个非镞索引的叶级包含了指向行数据页的指针。

在一个表中可以有多个非镞索引,你可以在以下几个情况下考虑使用非镞索引。

在有很多不同值的列上可以考虑使用非镞索引

例如:一个part_id列在一个part表中

select * from employee where emp_id = 'pcm9809f'

查询语句中用order by 子句的列上可以考虑使用镞索引

3 查询语句的设计

SQL Server优化器通过分析查询语句,自动对查询进行优化并决定最有效的执行方案。优化器分析查询语句来决定那个子句可以被优化,并针对可以被优化查询的子句来选择有用的索引。最后优化器比较所有可能的执行方案并选择最有效的一个方案出来。

在执行一个查询时,用一个where子句来限制必须处理的行数,除非完全需要,否则应该避免在一个表中无限制地读并处理所有的行。

例如下面的例子,

select qty from sales where stor_id=7131

是很有效的比下面这个无限制的查询

select qty from sales

避免给客户的最后数据选择返回大量的结果集。允许SQL Server运行满足它目的的函数限制结果集的大小是更有效的。

这能减少网络I/O并能提高多用户的相关并发时的应用程序性能。因为优化器关注的焦点就是where子句的查询,以利用有用的索引。在表中的每一个索引都可能成为包括在where子句中的侯选索引。为了最好的性能可以遵照下面的用于一个给定列column1的索引。

第一:在表中的column1列上有一个单索引

第二:在表中有多索引,但是column1是第一个索引的列不要在where子句中使用没有column1列索引的查询语句,并避免在where子句用一个多索引的非第一个索引的索引。

这时多索引是没有用的。

For example, given a multicolumn index on the au_lname, au_fname columns of the authors table in

the pubs database,

下面这个query语句利用了au_lname上的索引

SELECT au_id, au_lname, au_fname FROM authors

WHERE au_lname = 'White'

AND au_fname = 'Johnson'

SELECT au_id, au_lname, au_fname FROM authors

WHERE au_lname = 'White'

下面这个查询没有利用索引,因为他使用了多索引的非第一个索引的索引

SELECT au_id, au_lname, au_fname FROM authors

WHERE au_fname = 'Johnson'

原文转自:www.ltesting.net

篇7:SQLServer数据库学习笔记

1,exists和in的理解(参考/article/28922.htm)

exists:如果子查询中包括某一行,那么就为TRUE

in:如果操作数为TRUE等于表达式列表中的一个,那么就为TRUE

exists总是搞得不太明白

select 。。。from。。。where 。。。

where就相当于一个判断条件,只有where后面的表达式运算结果为TRUE,前面的才能select出来

EXISTS用于检查子查询是否至少会返回一行数据,该子查询实际上并不返回任何数据,而是返回值True或False

1: SELECT c.CustomerId, CompanyName 2: FROM Customers c 3: WHERE EXISTS( 4: SELECT OrderID FROM Orders o 5: WHERE o.CustomerID = cu.CustomerID)

像这样的EXISTS子查询中的SELECT什么根本不重要,因为子查询只是检查这个表中有没有满足WHERE后条件的行, 有就返回TRUE,没有就FALSE,所以很多EXISTS后都是SELECT的*

一行行的去判定,EXISTS返回的是TRUE,就是存在,则把这行的相关信息输出

1: select distinct 姓名 from xs 2: where not exists ( 3: select * from kc 4: where not exists ( 5: select * from xs_kc 6: where 学号=xs.学号 and 课程号=kc.课程号 )

分析下上面的查询语句:

把最外层的xs表里的记录一行一行的同中层一行一的笛卡尔乘积后拿到里面去检验

在最里层,如果xs_kc表里的某行有拿来检验的这行的学号,同时有中层拿来检验的课程号

就返回TRUE,说明这个这个学生选了这门课

中层如果某门课程没有收到返回的TRUE信息,说明这个名字和课程的搭配在xs_kc表中没有,或者说中层select出来的是没有被这个学生选择的课程信息,如果有这样的课程,就向最外层返回个TRUE

最外层在返回信息上加了not,即最外层找的是这样的一种学生:

他选择了所有的课程

最外层一行行的去检测,如果他满足这个条件,就输出他的姓名且只输出一次

我这是一层层的分析,还有么有什么别的办法?

2,select。。。into @。。。

和select @。。。 = 。。。应该是相同的吧

3,用AS为列重命名似乎比=更好点,和赋值区分开

4,用compute汇总的时候,如果是根据某列汇总的,先要order by此列,然后在compute相应信息,最后by此列

group或者compute的时候,如果by了某列,select里都要出现相同的列

区别是group的聚合函数在select行中(称为选择列表),而compute的聚合函数在compute行中,同时compute可以不带by,对所有行汇总

[SQLServer数据库学习笔记]

篇8:远程管理sqlserver的注册方法数据库教程

server|sqlserver

如果是在同一个局域网内的数据库可以直接操作第二个步骤它会自动搜索到局域网内的所以sqlserver数据库

但是如果是在不同局域网内的数据库就需要通过ip来访问步骤如下:

1、点击开始 -- 程序 -- Microsoft SQL Server -- 客户端网络实用工具 -- 另名 -- 点击添加 --- 网络库选取TCP/IP;服务器别名:数据库服务器的IP;服务器名称:数据库服务器的IP;端口默认1433(查清远程的端口是什么!) -- 确定

2、点击开始 -- 程序 -- Microsoft SQL Server -- 企业管理器 -- Mouse点 Microsoft SQL Servers -- mouse右键点 Sql Server 组;点新的sql server 注册.... -- 下一步 -- 增加主机IP,下一步---选“系统管理员给我分配的SQL Server登录信息....”. ,

远程管理sqlserver的注册方法数据库教程

。。。。。

ChangeAllObjectOwner数据库教程

SQLSERVER Pager store procedure分页存储过程数据库教程

项目管理数据库教程

复制监视器数据库教程

组合查询数据库教程

SQLServer数据库误删除数据的恢复

优化Oracle停机时间及数据库恢复数据库教程

InnoDB 中文参考手册 9 性能调整技巧数据库教程

删除Oracle 9i数据库数据库教程

预装入对象数据库教程

SQL Server数据库性能优化数据库教程(精选8篇)

欢迎下载DOC格式的SQL Server数据库性能优化数据库教程,但愿能给您带来参考作用!
推荐度: 推荐 推荐 推荐 推荐 推荐
点击下载文档 文档为doc格式
点击下载本文文档