报告论文:网站后台管理性能优化分析

网站后台管理性能优化分析

 一、前言

一个网站的生命在于其简单精美的前台界面以及性能优越的后台管理和维护。在这两者之间,后台管理和维护性能的优越性无可厚非是至关重要的,特别是中、大型的网站,后台管理和维护显得尤为重要。

既然网站后台的管理和维护具有如此重要的地位,那么,在网站的设计和建设过程中就应当投入更多的精力去进行合理的优化设计。网站的后台管理和维护主要表现在两个方面:一是网站前台与后台之间互联的管理和维护,二是网站后台数据库的管理和维护。

 

 

二、连接后台数据库的性能优化

ADOActiveX Data Object)是ASP的重要组件,内置于ASPASPDatabase Access组件与后台数据库进行连接。Database Access 组件通过 ADO 访问存储在数据库或其他表格化数据库结构中的信息。因此,与过去编写CGI程序访问数据库信息相比,ADO已成为当今开发者们最喜欢的恢复和修改SQL_SERVER数据库数据的常用Database Access 组件。然而,ADO的默认设置并不总是最优化的设置,要想开发出强大的基于Client/ServerWeb的应用程序,有必要研究一下如何提高它的性能。实践证明,可以从7个方面来提高ADO的性能。

 

1.     使用本地SQL SERVER OLE DB Provider属性

Microsoft 对应用程序访问各种各样的数据源所使用的方法是OLE DBOLE DB介于ODBC(开放式数据库连接标准)层和应用程序之间。在你的ASP页面中,ADO介于OLE DB之上的应用程序。你的ADO调用首先被送到OLE DB,然后送到ODBC层。OLE DB是一套组件对象模型(COM)接口。一般情况下,ADO默认,一个ADO Recordset 对象使用OLE DB Provider 作为 ODBC来连接SQL SERVER。然而,本地的OLE DB Provider SQL SERVER 提供了较短的代码路径,而这往往会较大地提高ADO 的性能.

 

2.复用现有的Connection 对象

如果正在开发一个APS页面的应用程序,在一个Command Recordset 对象的ActiveConnection 属性中复用现有的ADO Connection 对象。因为当ADO暗中打开或建立一个Connection 对象时,通过运用这种方法你可以避开一些额外的开销。

 

3.明确地定义各种参数

虽然ADO能够动态地决定一个Command 对象所使用的各种参数属性,较好地缩短开发周期,但是这种特性,在应用程序中非常典型地增加了服务器的环路,在一定程度上降低了ADO 的性能。所以,明确地定义一个参数的Type, Direction and Size 可以减少应用程序给服务器造成的环路数量。

 

4.调整缓冲区的大小

ADOCacheSize 影响服务器方面的Keyset游标及静态和动态的Recordsets。 在CacheSize的默认设置下,ADO在修改和合并操作时工作状态良好,但如果应用程序需要恢复大量的数据,就需要增加

这个值。缩减服务器的环路数,是提高ADOSQL SERVER应用程序性能的关键。

5.使用Command 对象代替游标

有时,使用游标来进行修改操作几乎是不可避免的。然而,修改游标可能带来额外的开销,从而降低性能。但如果试图使用包含着T-SQL InsertUpdatedelete 语句的Command 对象来对服务器进行发送修改操作可以使开发者得到较好的性能。

 

6.在Recordset对象中使用指针快速前移方法

最好的ADO数据更新性能来自于在Recordset对象中使用指针快速前移方法。一旦你设定一个Recordset 对象为前移,只读和带有值1CacheSize,ADO就会在该对象中自动生成一个快速前移的指针。这种方法使得大量的数据伴随着很低的开销从SQL Server流向Client 端。

 

7.使用最好的SQL

 

使用较好的SQL是从ADO和所有以SQL为基础的数据存取技术获得较好性能的最好方法。当你建立SQL一个语句,包含你真正需要的一些行和列的时候,充分利用SQL内置的存贮过程,可以使得服务器有效地处理所有的数据更新需求。

 

 

三、SQL Server索引优化后台数据库性能

 

大多数SQL Server表需要索引来提高数据的访问速度,如果没有索引,SQL Server要进行表格扫描读取表中的每一个记录才能找到索要的数据。索引可以分为簇索引和非簇索引,簇索引通过重排表中的数据来提高数据的访问速度,而非簇索引则通过维护表中的数据指针来提高数据的索引。簇索引 , 表中存储的数据按照索引的顺序存储 , 检索效率比普通索引高 , 但对数据新增 / 修改 / 删除的影响比较大非簇索引 , 不影响表中的数据存储顺序 , 检索效率比聚集索引低 , 对数据新增 / 修改 / 删除的影响很小.

 

在使用 SQL 时往往会陷入一个误区,即太关注于所得的结果是否正确,而忽略 了不同的实现方法之间可能存在的性能差异,这种性能差异在大型的或是复杂的数据库环境中(如联机事务处理 OLTP 或决策支持系统 DSS )中表现得尤为明显。不良的 SQL 往往来自于不恰当的索引设计、不充份的连接条件和不可优化的 where 子句。在对它们进行适当的优化后,其运行速度有了明显地提高!下面将从这三个方面分别进行总结:了更直观地说明问题,所有实例中的 SQL 运行时间均经过测试,不超过1秒的均 表示为( < 1 秒)。

 

Ⅰ、不合理的索引设计

例:表 record 620000 行,试看在不同的索引下,下面几个 SQL 的运行情况:

 

 1. date 上建有一非个簇索引

select count(*) from record where date >

'19991201' and date < '19991214'and amount >

2000 (25 )

select date,sum(amount) from record group by date

(55 )

select count(*) from record where date >

'19990901' and place in ('BJ','SH') (27 )

分析:

date 上有大量的重复值,在非簇索引下,数据在物理上随机存放在数据页上,在

范围查找时,必须执行一次表扫描才能找到这一范围内的全部行。

 

2. date 上的一个群集索引

select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000 14 秒)

select date,sum(amount) from record group by date

28 秒)

select count(*) from record where date >

'19990901' and place in ('BJ','SH') 14 秒)

分析:

在簇索引下,数据在物理上按顺序在数据页上,重复值也排列在一起,因而在范

围查找时,可以先找到这个范围的起末点,且只在这个范围内扫描数据页,避免了大范

围扫描,提高了查询速度。

 

3. place date amount 上的组合索引

select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000 26 秒)

select date,sum(amount) from record group by date

27 秒)

select count(*) from record where date >

'19990901' and place in ('BJ', 'SH') < 1 秒)

分析:

这是一个不很合理的组合索引,因为它的前导列是 place ,第一和第二条 SQL 没有引 用 place ,因此也没有利用上索引;第三个 SQL 使用了 place ,且引用的所有列都包含在组 合索引中,形成了索引覆盖,所以它的速度是非常快的。

 

4. date place amount 上的组合索引

select count(*) from record where date >

'19991201' and date < '19991214' and amount >

2000(< 1 )

select date,sum(amount) from record group by date

11 秒)

select count(*) from record where date >

'19990901' and place in ('BJ','SH') < 1 秒)

分析:

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

 

5. 总结:

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

. 有大量重复值、且经常有范围查询

between, >,< >=,< = )和 order by

group by 发生的列,可考虑建立群集索引;

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

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

 

Ⅱ、不充份的连接条件:

例:表 card 7896 行,在 card_no 上有一个非聚集索引,表 account 191122 行,在

account_no 上有一个非聚集索引,试看在不同的表连接条件下,两个 SQL 的执行情况:

select sum(a.amount) from account a,

card b where a.card_no = b.card_no 20 秒)

SQL 改为:

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 + (外层表 account 191122 * 内层表 card 上对应外层 表第一行所要查找的 3 页) =595907 I/O 在第二个连接条件下,最佳查询方案是将 card 作外层表, account 作内层表,利用 account 上的索引,其 I/O 次数可由以下公式估算为:

外层表 card 上的 1944 + (外层表 card 7896 * 内层表 account 上对应外层表每一行所要查找的 4 页) = 33528 I/O

可见,只有充份的连接条件,真正的最佳方案才会被执行。

 

总结:

1. 多表操作在被实际执行前,查询优化器会根据连接条件,列出几组可能的连接方

案并从中找出系统开销最小的最佳方案。连接条件要充份考虑带有索引的表、行数多的表;内外表的选择可由公式:外层表中的匹配行数 * 内层表中每一次查找的次数确定,乘 积最小为最佳方案。

2. 查看执行方案的方法 -- set showplanon ,打开 showplan 选项,就可以看到连 接顺序、使用何种索引的信息;想看更详细的信息,需用 sa 角色执行 dbcc(3604,310,302)

 

Ⅲ、不可优化的 where 子句

1. 例:下列 SQL 条件语句中的列都建有恰当的索引,但执行速度却非常慢:

select * from record where

substring(card_no,1,4)='5378'(13 )

select * from record where

amount/30< 1000 11 秒)

select * from record where

convert(char(10),date,112)='19991201' 10 秒)

分析:

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

select * from record where card_no like

'5378%' < 1 秒)

select * from record where amount

< 1000*30 < 1 秒)

 

select * from record where date= '1999/12/01'

< 1 秒)

你会发现 SQL 明显快起来!

2. 例:表 stuff 200000 行, id_no 上有非群集索引,请看下面这个 SQL

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

23 秒)

分析:

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

实践证明,表的行数越多,工作表的性能就越差,当 stuff 620000 行时,执行时 间竟达到 220 秒!还不如将 or 子句分开:

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

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

---- 得到两个结果,再作一次加法合算。因为每句都使用了索引,执行时间只有 3 秒,

620000 行下,时间也只有 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

 

直接算出结果,执行时间同上面一样快!

可见,所谓优化即 where 子句利用了索引,不可优化即发生了表扫描或额外开销。

总结可得:

1. 任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时

要尽可能将操作移至等号右边。

2.in or 子句常会使用工作表,使索引失效;如果不产生大量重复值,可以考虑把

子句拆开;拆开的子句中应该包含索引。

3. 要善于使用存储过程,它使 SQL 变得更加灵活和高效。

从以上这些例子可以看出, SQL 优化的实质就是在结果正确的前提下,用优化器可

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

 

 

四、其他SQL语句优化后台数据库性能

 

1.避免使用order bygroup by字句。
因为使用这两个子句会占用大量的临时空间(tempspace),如果一定要使用,可用视图、人工生成临时表的方法来代替。
如果必须使用,先检查memorytempdb的大小。
测试证明,特别要避免一个查询里既使用join又使用group by,速度会非常慢!

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


3
.消除对大型表行数据的顺序存取

在嵌套查询中,对表的顺序存取对查询效率可能产生致命的影响。比如采用顺序存取策略,一个嵌套3层的查询,如果每层都查询1000行,那么这个查询就要查询10亿行数据。避免这种情况的主要方法就是对连接的列进行索引。例如,两个表:学生表(学号、姓名、年龄……)和选课表(学号、课程号、成绩)。如果两个表要做连接,就要在学号这个连接字段上建立索引。

 
还可以使用并集来避免顺序存取。尽管在所有的检查列上都有索引,但某些形式的where子句强迫优化器使用顺序存取。下面的查询将强迫对orders表执行顺序操作:
SELECT
FROM orders WHERE (customer_num=104 AND order_num>1001) OR order_num=1008
虽然在customer_numorder_num上建有索引,但是在上面的语句中优化器还是使用顺序存取路径扫描整个表。因为这个语句要检索的是分离的行的集合,所以应该改为如下语句:
SELECT
FROM orders WHERE customer_num=104 AND order_num>1001
UNION
SELECT
FROM orders WHERE order_num=1008
这样就能利用索引路径处理查询。


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


5
.使用临时表加速查询
把表的一个子集进行排序并创建临时表,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。例如:
SELECT cust.name
rcvbles.balance……other columns
FROM cust
rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
AND cust.postcode>“98000”
ORDER BY cust.name
如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个临时文件中,并按客户的名字进行排序:
SELECT cust.name
rcvbles.balance……other columns
FROM cust
rcvbles
WHERE cust.customer_id = rcvlbes.customer_id
AND rcvblls.balance>0
ORDER BY cust.name
INTO TEMP cust_with_balance
然后以下面的方式在临时表中查询:
SELECT
FROM cust_with_balance
WHERE postcode>“98000”
临时表中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。
注意:临时表创建后不会反映主表的修改。在主表中数据频繁修改的情况下,注意不要丢失数据。

 
6
.用排序来取代非顺序存取
非顺序磁盘存取是最慢的操作,表现在磁盘存取臂的来回移动。SQL语句隐藏了这一情况,使得在写应用程序时很容易写出要求存取大量非顺序页的查询。有些时候,用数据库的排序能力来替代非顺序的存取能改进查询。

 

 

五、结束语

 

网站的后台管理性能是一个网站生存的灵魂所在。从网站的设计规划开始直到网站的生命结束,网站的后台管理性能一直是关注的重点。对网站整体性能的优化可以从很多方面入手,本文主要分析了从网站前、后台的互联和网站后台数据库SQL语句两个方面进行了初步的分析。这两个方面是是提高网站整体性能的重点,是必须首要考虑的问题。网站数据库和前、后台之间互联的性能得到了有效的提高,那么网站的整体性能必将得到很大的优化。

 

 

六、参考文献

 

戴一波.  Dreamweaver 8+ASP动态网站开发从基础到实践.  电子工业出版社,2006

  .  SQL Server 2000开发与管理.  人民邮电出版社,2006

     李凤蕾.  SQL Server 2005数据库系统开发.  人民邮电出版社,2007

     于志均.  数据库设计与管理基础.  北京:高等教育出版社,1990

 

原文地址:https://www.cnblogs.com/Gemgin/p/3136500.html