NOVOTS KMS 词汇表 Glossary    联系我们 Contact Us
查询 Search  
   
按类别浏览 Browse by Category
NOVOTS KMS .: 数据库 .: sql优化总结(转)

sql优化总结(转)

查询速度慢的原因很多,常见如下几种:
  1、没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)
  2I/O吞吐量小,形成了瓶颈效应。
  3、没有创建计算列导致查询不优化。
  4、内存不足

  5、网络速度慢
  6、查询出的数据量过大(可以采用多次查询,其他的方法降低数据量)
  7、锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷)
   8
sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。
  9、返回了不必要的行和列
 10、查询语句不好,没有优化

 

DBMS处理查询计划的过程是这样的:
1
 查询语句的词法、语法检查
2
 将语句提交给DBMS的查询优化器
3
 优化器做代数优化和存取路径的优化
4
 由预编译模块生成查询规划
5
 然后在合适的时间提交给系统处理执行
6
 最后将执行结果返回给用户其次,看一下SQL SERVER的数据存放的结构:一个页面的大小为8K(8060) 字节,8个页面为一个盘区,按照B树存放。

 

SQL优化的实质就是在结果正确的前提下用优化器可以识别的语句,充份利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述这些只是在应用层次的一种体现,深入研究还会涉及数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计。

 

一、索引

1、         索引的建立

缺省情况下建立的索引是非群集索引,但有时它并不是最佳的;合理的索引设计要建立在对各种查询的分析和预测上。一般来说:

(1) 有大量重复值、且经常有范围查询(between, >;,< >;=,< =) order bygroup by发生的列,可考虑建立群集索引

索引

语句

时间

date上有个非群集索引

select count(*)  from record where date >'19991201' and date < '19991214'and amount >2000

(25)

date上的一个群集索引

select count(*)  from record where date >
'19991201' and date < '19991214' and amount >2000

(14)

在群集索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范围扫描,提高了查询速度。

(2) 经常同时存取多列,且每列都含有重复值可考虑建立组合索引

(3) 组合索引要尽量使关键查询形成索引覆盖,其前导列一定是使用最频繁的列

索引

语句

时间

placedateamount组合索引

select count(*)  from record where date >'19991201' and date < '19991214' and amount >2000

(26)

dateplaceamount组合索引

select count(*)  from record where date>'19991201' and date < '19991214' and amount >2000

(< 1)

它将date作为前导列,使每个SQL都可以利用索引,并且在第一和第三个SQL中形成了索引覆盖,因而性能达到了最优。

(4) 在经常进行连接,但是没有指定为外键的列上建立索引,而不经常连接的字段则由优化器自动生成索引。

(5) 在频繁进行排序或分组(即进行group byorder by操作) 的列上建立索引。

(6) 在条件表达式中经常用到的不同值较多的列上建立检索,在不同值少的列上不要建立索引。比如在雇员表的性别列上只有两个不同值,因此就无必要建立索引。如果建立索引不但不会提高查询效率,反而会严重降低更新速度。

(7) 如果待排序的列有多个,可以在这些列上建立复合索引(compound index)

(8) 根据查询条件,建立索引,优化索引、优化访问方式。

2、索引应该尽量小,使用字节数小的列建索引好(参照索引的创建) ,不要对有限的几个值的字段建单一索引如性别字段 索引越小越好

3、索引不能建得太多和太大。

4、在取值范围比较小的情况下,数字型字段上基本没有建立索引的必要。建立索引还可能会增加表的负担,查询速度甚至会减慢。

5、在排序过程中,索引的使用非常关键。建议使用聚集索引。

二、SQL子句

尽可能编写优化器可以优化的语句。

1、 SELECT子句

() 在查询Select语句中用Where字句限制返回的行数,避免表扫描,如果返回不必要的数据,浪费了服务器的I/O资源,加重了网络的负担降低性能。如果表很大,在表扫描的期间将表锁住,禁止其他的联接访问表,后果严重。用select top 100 / 10 Percent 来限制用户返回的行数或者SET ROWCOUNT来限制操作的行。

() 查询时不要返回不需要的列。字段提取要按照需多少、提多少的原则,避免“select *”,尽量使用“select 字段1,字段2,字段3........”。实践证明:每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。

(3) 避免返回大结果集的查询

(4) 检索紧跟在 INSERT SQL 之后且位于同一连接上的 IDENTITY

SELECT @@IDENTITY

例如:

SET NOCOUNT ON;// 表示返回的记录集有一行和一列,其中包含了这个新的 IDENTITY 值。

INSERT INTO Products (ProductName)  VALUES ('Chalk')

SELECT @@IDENTITY

 

2、 WHERE子句

(1)   函数名和列名分开

任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。

语句

时间

select * from record where substring(card_no,1,4) ='5378'

(13秒)

select * from record where card_no like  '5378%'

(< 1)

where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用该列上面的索引;如果这些结果在查询编译时就能得到,那么就可以被SQL优化器优化,使用索引,避免表搜索。

() 表达式等号右边的字段值应尽量与等号左边的字段数据类型完全一致

分析select emp_name form employee where salary > 3000 在此语句中若salaryFloat类型的,则优化器对其进行优化为Convert(float,3000) ,因为3000是个整数,我们应在编程时使用3000.0而不要等运行时让DBMS进行转化。同样字符和整型数据的转换。

(3) WHERE 子句中减少需要分组的行数而避免在HAVING子句中进行

假设您将按区域对所有销售人员进行分组并将他们的销售额进行小计,但是您只想要那些数据库中标记为处于活动状态的销售人员。您可以按区域对销售人员分组,并使用 HAVING 子句消除那些未处于活动状态的销售人员,也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减少需要分组的行数,所以比在HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的筛选会强制查询对那些在WHERE子句中会被去除的数据进行分组。

(4) WHERE子句中的连接顺序

sql解析器采用自下而上的顺序解析WHERE子句,根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾

SELECT … FROM emp e WHERE sal>50000 AND job=‘MANAGER’AND 25<(SELECT COUNT(*)  FROM emp WHERE mgr=e.empno) ;

效率低于

SELECT… FROM emp e WHERE 25<(SELECT COUNT(*)  FROM emp WHERE mgr=e.empno)  AND sal>50000 AND job=‘MANAGER’;

WHERE子句后面的条件顺序对大数据量表的查询会产生直接的影响,如

 

Select * from zl_yhjbqk where dy_dj = '1K以下' and xh_bz=1

Select * from zl_yhjbqk where xh_bz=1 and dy_dj = '1K以下'

以上两个SQLdy_djxh_bz两个字段都没进行索引,所以执行的时候都是全表扫描,第一条SQLdy_dj = '1KV以下'条件在记录集内比率为99%,而xh_bz=1的比率只为0.5%,在进行第一条SQL的时候99%条记录都进行dy_djxh_bz的比较,而在进行第二条SQL的时候0.5%条记录都进行dy_djxh_bz的比较,以此可以得出第二条SQLCPU占用率明显比第一条低。

(5) where语句条件顺序

有索引的列优先,都有索引的看查询出来的数据量,少的优先。

(6) 条件中最好不要使用ORIN

3、 JOIN子句

(1)  多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方案并从中找出系统开销最小的最佳方案。

(2)  连接条件要充份考虑带有索引的表、行数多的表;

(3)  内外表的选择可由公式:外层表中的匹配行数*内层表中每一次查找的次数确定,乘积最小为最佳方案

card7896行,在card_no上有一个非聚集索引,表account191122行,在 account_no上有一个非聚集索引

语句

时间

select sum(a.amount)  from account a,card b where a.card_no = b.card_no

20秒

select sum(a.amount)  from account a,card b where a.card_no = b.card_no  and a.account_no=b.account_no

< 1

在第一个连接条件下,最佳查询方案是将account作外层表,card作内层表,利用card上的索引,其I/O次数可由以下公式估算为:
----
外层表account上的22541+(外层表account191122*内层表card上对应外层表第一行所要查找的3) =595907I/O
----
在第二个连接条件下,最佳查询方案是将card作外层表,account作内层表,利用account上的索引,其I/O次数可由以下公式估算为:
----
外层表card上的1944+(外层表card7896*内层表account上对应外层表每一行所要查找的4) = 33528I/O

(什么是内外表??行数少的表作为外表?行数与页数的转换???)
(4)
查看执行方案的方法-- set showplanon,打开showplan选项,就可以看到连接顺序、使用何种索引的信息;想看更详细的信息,需用sa角色执行dbcc(3604,310,302)

(5) 外连接时避免外健值为空

避免使用 LEFT JOIN 时速度降低的最简单方法是尽可能多地围绕它们设计数据库。例如,假设某一产品可能具有类别也可能没有类别。如果 Products 表存储了其类别的 ID,而没有用于某个特定产品的类别,则您可以在字段中存储 NULL 值。然后您必须执行 LEFT JOIN 来获取所有产品及其类别。您可以创建一个值为“No Category”的类别,从而指定外键关系不允许 NULL 值。

(6) existsinner join

exists的效率依赖于匹配度,它对主表的每行记录会对子表进行扫描,若匹配则返回。举个极端情况,如果子表每次都要进行全表扫描才能找到匹配,这时exists的效率就比较低。

inner join 效率比较稳定,若对子表匹配度不了解的情况下建议用inner join
(7)
如果连接字段不是主键/外键形式的,还注意索引的建立。

4ORDER BY子句

() 没有必要时不要用ORDER BY,这些动作可以改在客户端执行。它们增加了额外的开销。

(2) order by按聚集索引列排序效率最高。一个sqlserver数据表只能建立一个聚集索引,一般默认为ID,也可以改为其它的字段。

(3) 排序的列尽量来自同一个表。

() order by子句中列的次序与索引的次序一致。

5GROUP BY子句

(1) 一般在GROUP BY HAVING字句之前就能剔除多余的行,所以尽量不要用它们来做剔除行的工作。他们的执行顺序应该如下最优:select Where字句选择所有合适的行,Group By用来分组个统计行,Having字句用来剔除多余的分组。这样Group By Having的开销小,查询快.对于大的数据行进行分组和Having十分消耗资源。如果Group BY的目的不包括计算,只是分组,那么用Distinct更快

() group by子句中列的次序与索引的次序一致。

6、LIKE子句

如果是使用like进行查询的话,简单的使用index是不行的,但是全文索引() ,耗空间。
like 'a%'
使用索引
like '%a'
不使用索引
 like '%a%' 查询时,查询耗时和字段值总长度成正比,所以不能用CHAR类型,而是VARCHAR。对于字段的值很长的建全文索引。

7、IN、OR、EXITS、BETWEEN...AND

() IN后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,减少判断的次数

() in ,not in,<>,is null,is not null 等由于不会走索引,尽量不要使用;如果不产生大量重复值,可以考虑把子句拆开;拆开的子句中应该包含索引。存储过程使SQL变得更加灵活和高效。

语句

时间

select count(*)  from stuff where id_no in('0','1')

(23秒)

select count(*)  from stuff where id_no='0'

UNION
select count(*)  from stuff where id_no='1'

(4秒)

create proc count_stuff as
declare @a int
declare @b int
declare @c int
declare @d char(10)
begin
select @a=count(*)  from stuff where id_no='0'
select @b=count(*)  from stuff where id_no='1'
end
select @c=@a+@b
select @d=convert(char(10) ,@c)
print @d

(4秒)

where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1') 转化为id_no ='0' or id_no='1'来执行。我们期望它会根据每个or子句分别查找,再将结果相加,这样可以利用id_no上的索引;但实际上(根据showplan) ,它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用id_no上索引,并且完成时间还要受tempdb数据库性能的影响。

OR的字句可以分解成多个查询,并且通过UNION 连接多个查询。他们的速度只同是否使用索引有关,如果查询需要用到联合索引,用UNION all() 执行的效率更高.多个OR的字句没有用到索引,改写成UNION的形式再试图与索引匹配。一个关键的问题是否用到索引。

注意:在大数据量的情况下,or语句的效率比<=语句的效率差很多,而Union语句的效率最低。

(2)   Between在某些时候比IN速度更快

Between能够更快地根据索引找到范围。用查询优化器可见到差别。 select * from chineseresume where title in ('','')  Select * from chineseresume where between '' and '' 是一样的。由于in会在比较多次,所以有时会慢些。

(3) IN适合于外表大而内表小的情况;EXISTS() 适合于外表小而内表大的情况。

(4) ("IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'",因为他们不走索引全是表扫描。

(5) NOT IN会多次扫描表,使用EXISTSNOT EXISTS IN , LEFT OUTER JOIN 来替代,特别是左连接,ExistsIN更快,最慢的是NOT操作.如果列的值含有空,以前它的索引不起作用,现在2000的优化器能够处理了。相同的是IS NULL“NOT", "NOT EXISTS", "NOT IN"能优化她,而”<>”等还是不能优化,用不到索引。

7、 UNION

UNionUNion all 的区别。UNION all

在没有必要时不要用,UNION会使查询变慢

8、 DISTINCT

(1) 注意使用DISTINCT,在没有必要时不要用,它同UNION一样会使查询变慢。重复的记录在查询里是没有问题的。

(2) 使用 DISTINCT 关键字查找数据行的单独报表,来代替使用 GROUP BY 子句。在这种情况下,使用 DISTINCT 关键字的 SQL 效率更高。请在需要计算聚合函数(SUMCOUNTMAX ) 的情况下再使用 GROUP BY

(3) 如果您的查询总是自己返回一个唯一的行,则不要使用 DISTINCT 关键字。在这种情况下,DISTINCT 关键字只会增加系统开销。

9、 聚合函数

(1) 需要查询的结果预先计算好放在表中,查询的时候再SELECT。这在SQL7.0以前是最重要的手段。例如医院的住院费计算。

() MIN()   MAX() 能使用到合适的索引

() 不要在一句话里再三的使用相同的函数,浪费资源,结果放在变量里再调用更快。

() SELECT COUNT(*) 的效率教低,尽量变通他的写法,而EXISTS() 。同时请注意区别: select count(Field of null)  from Table select count(Field of NOT null)  from Table 的返回值是不同的。

10、         视图

尽量少用视图,它的效率低。对视图操作比直接对表操作慢,可以stored procedure来代替是视图。特别的是不要用视图嵌套,嵌套视图增加了寻找原始资料的难度。我们看视图的本质:它是存放在服务器上的被优化好了的已经产生了查询规划的SQL。对单个表检索数据时,不要使用指向多个表的视图,直接从表检索或者仅仅包含这个表的视图上读,否则增加了不必要的开销,查询受到干扰.为了加快视图的查询,MsSQL增加了视图索引的功能。

11、         注释

SQL的注释申明对执行没有任何影响

12、         插入较大的二进制值使用存储过程

如果要插入大的二进制值到Image列,使用存储过程,千万不要用内嵌INsert来插入(不知JAVA是否) 。因为这样应用程序首先将二进制值转换成字符串(尺寸是它的两倍) ,服务器受到字符后又将他转换成二进制值.存储过程就没有这些动作: 方法:Create procedure p_insert as insert into table(Fimage)  values (@image) ,在前台调用这个存储过程传入二进制参数,这样处理速度明显改善。

14.FROM子句

(1) 选择最有效率的表名顺序

sql解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表 driving table) 将被最先处理。在FROM子句中包含多个表的情况下,你必须选择记录条数最少的表作为基础表。

如果tab2中记录数明显高于tab1,用SELECT COUNT(*)  FROM tab2, tab1

效率明显优于SELECT COUNT(*)  FROM tab1, tab2

三、T-SQL

1、存储过程

存储过程,它使SQL变得更加灵活和高效。

2、触发器

3、光标

尽可能不使用光标,它占用大量的资源。如果需要row-by-row地执行,尽量采用非光标技术,如:在客户端循环,用临时表,Table变量,用子查询,用Case语句等等。

游标可以按照它所支持的提取选项进行分类:

只进 必须按照从第一行到最后一行的顺序提取行。FETCH NEXT 是唯一允许的提取操作,也是默认方式。

可滚动性 可以在游标中任何地方随机提取任意行。游标的技术在SQL2000下变得功能很强大,他的目的是支持循环。有四个并发选项:READ_ONLY:不允许通过游标定位更新(Update) ,且在组成结果集的行中没有锁。OPTIMISTIC WITH valueS:乐观并发控制是事务控制理论的一个标准部分。乐观并发控制用于这样的情形,即在打开游标及更新行的间隔中,只有很小的机会让第二个用户更新某一行。当某个游标以此选项打开时,没有锁控制其中的行,这将有助于最大化其处理能力。如果用户试图修改某一行,则此行的当前值会与最后一次提取此行时获取的值进行比较。如果任何值发生改变,则服务器就会知道其他人已更新了此行,并会返回一个错误。如果值是一样的,服务器就执行修改。 选择这个并发选项OPTIMISTIC WITH ROW VERSIONING:此乐观并发控制选项基于行版本控制。使用行版本控制,其中的表必须具有某种版本标识符,服务器可用它来确定该行在读入游标后是否有所更改。

SQL Server 中,这个性能由 timestamp 数据类型提供,它是一个二进制数字,表示数据库中更改的相对顺序。每个数据库都有一个全局当前时间戳值:@@DBTS。每次以任何方式更改带有 timestamp 列的行时,SQL Server 先在时间戳列中存储当前的 @@DBTS 值,然后增加 @@DBTS 的值。如果某 个表具有 timestamp 列,则时间戳会被记到行级。服务器就可以比较某行的当前时间戳值和上次提取时所存储的时间戳值,从而确定该行是否已更新。服务器不必比较所有列的值,只需比较 timestamp 列即可。

四、

1、临时表

(1)  少用临时表,尽量用结果集和Table类性的变量来代替临时表,Table 类型的变量比临时表好

() 当用SELECT INTO时,它会锁住系统表(sysobjectssysindexes等等) ,阻塞其他的连接的存取。创建临时表时用显示申明语句,而不是 select INTO. drop table t_lxh begin tran select * into t_lxh from chineseresume where name = 'XYZ' --commit 在另一个连接中SELECT * from sysobjects可以看到 SELECT INTO 会锁住系统表,Create table 也会锁系统表(不管是临时表还是系统表) 。所以千万不要在事物内使用它!!!这样的话如果是经常要用的临时表请使用实表,或者临时表变量。(select … into temp tname???)

() 临时表与内嵌视图

语句

时间

CREATE TABLE #Temp1 (OrderID INT NOT NULL, _

                     OrderDate DATETIME NOT NULL)

INSERT INTO #Temp1 (OrderID, OrderDate)

SELECT     TOP 5 o.OrderID, o.OrderDate

FROM Orders o ORDER BY o.OrderDate DESC

SELECT     p.ProductName, SUM(od.Quantity)  AS ProductQuantity

FROM     #Temp1 t

    INNER JOIN [Order Details] od ON t.OrderID = od.OrderID

    INNER JOIN Products p ON od.ProductID = p.ProductID

GROUP BY p.ProductName

ORDER BY p.ProductName

DROP TABLE #Temp1

导致此查询进行大量 I/O 操作和磁盘访问

SELECT p.ProductName,

    SUM(od.Quantity)  AS ProductQuantity

FROM     (

    SELECT TOP 5 o.OrderID, o.OrderDate

    FROM     Orders o

    ORDER BY o.OrderDate DESC

    )  t

    INNER JOIN [Order Details] od ON t.OrderID = od.OrderID

    INNER JOIN Products p ON od.ProductID = p.ProductID

GROUP BY    p.ProductName

ORDER BY    p.ProductName

查询效率更高,而且长度更短。临时表会消耗大量资源。如果只需要将数据联接到其他查询,则可以试试使用内嵌视图,以节省资源。

2、数据表

(1) 纵向、横向分割表,减少表的尺寸(sp_spaceuse)

(2) 不要对同一查询内的单个表使用多个别名以模拟索引交叉。因为 SQL Server 会自动考虑索引交叉并且可以在同一查询内的相同表上使用多个索引。

 

五、SQL语句的执行与提交

1、一次更新多条记录比分多次更新每次一条快,就是说批处理好

2、Rollback:回滚所有的事物。 Commit:提交当前的事物. 没有必要在动态SQL里写事物,如果要写请写在外面如: begin tran exec(@s)  commit trans 或者将动态SQL 写成函数或者存储过程。

3、尽量将数据的处理工作放在服务器上,减少网络的开销,如使用存储过程。存储过程是编译好、优化过、并且被组织到一个执行规划里、且存储在数据库中的SQL语句,是控制流语言的集合,速度当然快。反复执行的动态SQL,可以使用临时存储过程,该过程(临时表) 被放在Tempdb中。以前由于SQL SERVER对复杂的数学计算不支持,所以不得不将这个工作放在其他的层上而增加网络的开销。如果返回大的结果采用存储过程

 

六、数据库设计

1、把数据、日志、索引放到不同的I/O设备上() ,增加读取速度,以前可以将Tempdb应放在RAID0上,SQL2000不在支持。数据量(尺寸) 越大,提高I/O越重要。

2、对于大的数据库不要设置数据库自动增长,它会降低服务器的性能

七、DBMS查询优化

1、         使用Query Analyzer,查看SQL语句的查询计划和评估分析是否是优化的SQL。一般的20%代码占据了80%的资源,我们优化的重点是这些慢的地方。

2、         Profiler来跟踪查询,得到查询所需的时间,找出SQL的问题所在;用索引优化器优化索引

3、         sp_configure 'query governor cost limit'或者SET QUERY_GOVERNOR_COST_LIMIT来限制查询消耗的资源。当评估查询消耗的资源超出限制时,服务器自动取消查询,在查询之前就扼杀掉。 SET LOCKTIME设置锁的时间

4、         数据库有一个原则是代码离数据越近越好,所以优先选择Default,依次为Rules,Triggers, Constraint(约束如外健主健CheckUNIQUE……,数据类型的最大长度等等都是约束) ,Procedure.这样不仅维护工作小,编写程序质量高,并且执行的速度快。

5、         当服务器的内存够多时,配制线程数量 = 最大连接数+5() ,这样能发挥最大的效率;否则使用 配制线程数量<最大连接数启用SQL SERVER的线程池来解决,如果还是数量 = 最大连接数+5,严重的损害服务器的性能。

6、         sys.dm_db_index_usage_stats sys.dm_exec_query_stats 动态管理视图

(1) 数据库引擎优化顾问

sys.dm_db_index_usage_stats 收集有关 SQL Server 实例上现有索引的索引使用信息。sys.dm_exec_query_stats 返回有关缓存查询计划的聚合性能统计信息。它可捕获诸如缓存计划已执行的时间、缓存计划进行时所执行的逻辑和物理读取操作数等信息。

(2) 数据库引擎优化顾问是一个独立的工具,可对整个 SQL Server 工作负荷进行分析,并针对物理设计结构(例如索引、索引视图或分区) 的配置生成建议。

八、升级硬件

1、         提高网速;

2、         扩大服务器的内存,Windows 2000SQL server 2000能支持4-8G的内存。

3、         配置虚拟内存:虚拟内存大小应基于计算机上并发运行的服务进行配置。运行 Microsoft SQL Server™ 2000 时,可考虑将虚拟内存大小设置为计算机中安装的物理内存的 1.5 倍。如果另外安装了全文检索功能,并打算运行 Microsoft 搜索服务以便执行全文索引和查询,可考虑:将虚拟内存大小配置为至少是计算机中安装的物理内存的 3 倍。将 SQL Server max server memory 服务器配置选项配置为物理内存的 1.5 (虚拟内存大小设置的一半)

4、   增加服务器CPU个数;但是必须明白并行处理串行处理更需要资源例如内存。使用并行还是串行程是MsSQL自动评估选择的。单个任务分解成多个任务,就可以在处理器上运行。例如耽搁查询的排序、连接、扫描和GROUP BY字句同时执行,SQL SERVER根据系统的负载情况决定最优的并行等级,复杂的需要消耗大量的CPU的查询最适合并行处理。但是更新操作UPDATE,INSERTDELETE还不能并行处理。

九、其他补充

1、         填充因子

注意填充因子要适当(最好是使用默认值0)

2、         避免相关子查询 
一个列的标签同时在主查询和where子句中的查询中出现,那么很可能当主查询中的列值改变之后,子查询必须重新查询一次。查询嵌套层次越多,效率越低,因此应当尽量避免子查询。如果子查询不可避免,那么要在子查询中过滤掉尽可能多的行。  

3、             避免困难的正规表达式
MATCHES
LIKE关键字支持通配符匹配,技术上叫正规表达式。但这种匹配特别耗费时间。例如:SELECT FROM customer WHERE zipcode LIKE “98_ _ _”  
即使在zipcode字段上建立了索引,在这种情况下也还是采用顺序扫描的方式。如果把语句改为SELECT FROM customer WHERE zipcode >;“98000”,在执行查询时就会利用索引来查询,显然会大大提高速度。
另外,还要避免非开始的子串。例如语句:SELECT FROM customer WHERE zipcode[23] >;“80”,在where子句中采用了非开始子串,因而这个语句也不会使用索引。 


这篇文章对你多有用?

相关文章

article SQL优化
(1)...

(No rating)  10-9-2009    Views: 1269   
article sql优化总结(转)

(No rating)  2-24-2013    Views: 953   
article sql优化总结(转)

(No rating)  2-24-2013    Views: 938   

用户评语

添加评语
当前还没有评语.


.: .: .: .: .:
[ 登陆 ]
北京护航科技有限公司 2006

Novots Technologies Limited