|
提高数据库访问速度 |
来源:转载 人气:900 录入时间:2007-11-8 |
3 提高数据库访问速度(以SQL数据库为例)
客户机程序一般采用VC++,VB,PowerBuilder,Delphi等支持访问数据库的集成开发环境进行开发。在编写客户端程序时,一般通过ODBC(Open Database Connectibvity) API,RDO(Remote Data Objects) [5],ADO(ActiveX Data Objects) [5]访问数据库,查询或修改数据库中的数据。其中ODBC API是被人们广泛接受的用于数据库访问的应用程序编程接口。具有访问数据库速度快效率高,但编程复杂的特点;远程数据对象(RDO)对ODBC API函数进行了封装,为编程人员提供了一个访问远程数据库的高级接口,在程序中通过该对象可轻松对数据库进行远程访问。组件对象(ADO)不仅继承而且发展了RDO,它不但具有访问远程数据库的能力,而且还具有访问其它数据提供者(不一定是数据库,可能是其他文件或其他应用程序所提供的数据)的能力。在VB中可很方便的使用RDO和ADO来访问数据库,但访问数据库效率不高,速度较慢,灵活性也差。为了满足系统的要求经常需要提高访问数据库的速度,具体方法有:
3.1 使用ODBC API函数
由于ODBC API函数的入口参数表中有些参数需要传递指针,而VB不支持指针,因此在VB中调用ODBC API函数会有一定的限制。另外,VB的字符串内存存储格式与C语言不同,而ODBC API函数是用C语言开发的,这也限制了VB和ODBC API函数之间的数据交换。为此需要开发一个动态链接库(Dynamic Link Library - DLL),编制二个API函数分别以获取参数指针和支持数据交换,从而实现在该动态链接库的支持下,在VB中直接调用ODBC API函数的目的。
可以使用VC++6.0开发动态链接库。VC++6.0可开发三种类型的动态链接库:Win32 DLL、常规 MFC DLL、扩展 MFC DLL。其中Win32 DLL、常规 MFC DLL可被任意Win32编程环境(包括Visual Basic 6.0版)加载使用。常规 MFC DLL在发行时必须附带MFC42.DLL库,而Win32 DLL可单独发行[3]。如果只提供给VB编程环境使用,可建立Win32 DLL即可。
具体的开发步骤为:利用VC++6.0编程环境的AppWizard创建一个简单Win32 DLL工程,工程名为SQLAPI,在此基础上加入自己的代码。代码如下:
#include "stdafx.h"
#define DLLEXPORT extern "C" __declspec( dllexport) //定义导出宏
BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved)
{ return TRUE; }
DLLEXPORT long __stdcall GetAddress(void * Address) //按地址传送
{ return (long) Address; }//将地址强制转换为长整形
DLLEXPORT long __stdcall strCopyToByte (char * BytesAddress,char * strAddress)
{ return (long) strcpy(BytesAddress, strAddress); }//将字符串传送到指定地址
经编译链接生成SQLAPI.DLL动态链接库,将其拷贝到C:\WINDOWS\SYSTEM(对于Windows) 或C:\WINNT\SYSTEM32(对于Windows NT 或2000)目录下,这样就可在VB中调用这两个API函数实现对ODBC API的调用。ODBC调用的一般流程为:
1连接至数据源:分配环境句柄、设置环境属性、分配联接句柄、联接数据源和设置联接属性。
2初始化应用程序:分配语句句柄、设置语句属性,必要时进行数据绑定。
3建立和执行SQL语句:a) 建立SQL语句,或使用硬编码的SQL语句。b) 如果SQL语句含有参数,将每个参数绑定至应用程序变量。c) 用SQLExecDirect执行该语句。如果语句要多次执行,则进行语句准备,并用SQLExecute来执行。
使用API函数可以加快数据库的访问,提高效率,另外也要注意SQL语句的语法优化。对于巨表和多表访问,SQL语句的语法优化对访问速度的影响会显得尤为重要。
3.2 SQL优化
应从数据库端和客户端程序两方面入手,提高访问SQL数据库的速度,提高查询和修改数据库数据的效率。在数据库的表中记录数很多时,访问速度尤其重要,由于SQL数据库采用先进的索引技术和高效的查询算法,因此在保证结果正确的同时,要注意选用性能最佳的实现方法。其中可以通过对数据库的索引,多表间的连接和where子句进行适当的优化,使运行速度大大提高,同时可使用存储过程来使SQL变得更加灵活和高效。
SQL数据库可高效处理成批和成组的数据,而对于单个数据处理则效率低下,因此,在编写客户端程序时,应尽量将数据成批(成组)地送往数据库,或成批(成组)地查询数据。另外,在客户端,使用SQL语句也存在优化问题。如:
dim mValue as Single, strSQL as string
mValue=12.34
strSQL=”UPDATE tablename SET value = “+str(mValue)+” WHERE name=’Generator’”
SQLExecDirect(语句句柄, strSQL ,SQL_NTS);
该语句将表tablename中name=’ Generator’记录的value值更新为12.34,该操作在程序运行中经过两次转换,首先将单精度数转换为字符串,和其他字符串合并后传递给ODBC 驱动程序,驱动程序又将字符串再转换为ODBC特有的数据格式,如更新大量数据则花费在转换数据格式上的系统开销很大,应尽量避免编写上述代码。对于多次常用语句应进行语句准备,以后可多次使用。
一般来说,针对有大量重复值、且经常有范围查询(between, >,< ,>=,< =)和order by、group by发生的列,建立非缺省的群集索引可能会使性能更佳,而对于经常同时存取多列,且每列都含有重复值的情况可考虑建立组合索引,注意组合索引要尽量使关键查询形成索引覆盖,其前导列一定要是使用最频繁的列。
在进行多表操作时,可在执行前根据连接条件,使用查询优化器列出几组可能的连接方案并从中找出系统开销最小的最佳方案。连接条件要充分考虑带有索引的表、行数多的表。内外表的选择可由下列公式确定。其中乘积最小的方案为最佳。
乘积=外层表中的匹配行数*内层表中每一次查找的次数
在where子句中,任何对列的操作都将导致表扫描,这些操作包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。假设有如下两个SQL语句,其条件语句中的列value已建有恰当的索引
语句1:select * from Table1 where value/30<100
语句2:select * from Table1 where value<100*30
在表中数据很多时,可明显看出语句2的运行速度比语句1快得多,这是因为where子句中对列的任何操作结果都是在SQL运行时逐列计算得到的,因此它不得不进行表搜索,而没有使用已建在该列上的索引。如果在查询编译时就能得到这些列的操作结果,那么就可以被SQL优化器优化,从而使用索引,避免表搜索,如语句2所示。
在where条件中in、or子句常会使用临时数据库的工作表,使索引失效;如果子句拆开后不产生大量重复值,可以考虑把子句拆开来优化运行,拆开的子句中应该包含索引。例如,假设在表Parts中有200000行记录,在类型字段Type上有非群集索引,则针对SQL语句:select count(amount) from Parts where Type in('0','1'),因为其where条件中的'in'在逻辑上相当于'or',所以语法分析器会将in ('0','1')转化为Type ='0' or Type ='1'来执行。我们原来期望它会根据每个or子句分别查找,再将结果相加,从而可以利用Type字段上的索引;但实际上它却采用了"OR策略",即先取出满足每个or子句的行,存入临时数据库的工作表中,再建立唯一索引以去掉重复行,最后从这个临时表中计算结果。因此,实际过程没有利用Type字段上的索引,并且完成时间还要受tempdb数据库性能的影响。
SQL优化的实质就是在结果正确的前提下,用优化器可以识别的语句,尽量减少类型转换和计算,充分利用索引,减少表扫描的I/O次数,尽量避免表搜索的发生。其实SQL的性能优化是一个复杂的过程,上述内容只是在应用层次的一些体现,深入研究还会涉及其它内容如数据库层的资源配置、网络层的流量控制以及操作系统层的总体设计等。
|
|
|