百万数据级快速查询优化技巧.docx

上传人:b****3 文档编号:3884591 上传时间:2022-11-26 格式:DOCX 页数:36 大小:37.77KB
下载 相关 举报
百万数据级快速查询优化技巧.docx_第1页
第1页 / 共36页
百万数据级快速查询优化技巧.docx_第2页
第2页 / 共36页
百万数据级快速查询优化技巧.docx_第3页
第3页 / 共36页
百万数据级快速查询优化技巧.docx_第4页
第4页 / 共36页
百万数据级快速查询优化技巧.docx_第5页
第5页 / 共36页
点击查看更多>>
下载资源
资源描述

百万数据级快速查询优化技巧.docx

《百万数据级快速查询优化技巧.docx》由会员分享,可在线阅读,更多相关《百万数据级快速查询优化技巧.docx(36页珍藏版)》请在冰豆网上搜索。

百万数据级快速查询优化技巧.docx

百万数据级快速查询优化技巧

 

百万数据级快速查询优化技巧

 

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where及orderby涉及的列上

 

建立索引。

 

2.应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而

 

进行全表扫描,如:

 

selectidfromtwherenumisnull

 

可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:

 

selectidfromtwherenum=0

 

3.应尽量避免在where子句中使用!

=或<>操作符,否则将引擎放弃使用索引而进行全表扫

 

描。

 

4.应尽量避免在where子句中使用or来连接条件,否则将导致引擎放弃使用索引而进行

 

全表扫描,如:

 

selectidfromtwherenum=10ornum=20

 

可以这样查询:

 

select

id

from

t

where

num=10

union

all

select

id

from

t

where

num=20

 

5.in和notin也要慎用,否则会导致全表扫描,如:

 

selectidfromtwherenumin(1,2,3)

 

对于连续的数值,能用between就不要用in了:

 

selectidfromtwherenumbetween1and3

 

6.下面的查询也将导致全表扫描:

 

selectidfromtwherenamelike'%abc%'

 

若要提高效率,可以考虑全文检索。

 

7.如果在

 

where

 

子句中使用参数,也会导致全表扫描。

因为

 

SQL

 

只有在运行时才会解析

局部变量,但优化程序不能将访问计划的选择推迟到运行时;

它必须在编译时进行选择。

而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。

 

如下面语句将进行全表扫描:

 

selectidfromtwherenum=@num

 

可以改为强制查询使用索引:

 

selectidfromtwith(index(索引名))wherenum=@num

 

8.应尽量避免在where子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行

 

全表扫描。

如:

 

selectidfromtwherenum/2=100

 

应改为:

 

selectidfromtwherenum=100*2

 

9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全

 

表扫描。

如:

 

select

id

from

t

where

substring(name,1,3)='abc'--name

以abc

开头的id

select

id

from

t

where

datediff(day,createdate,'2005-11-30')=0--

2005-11-30?

生成的id

应改为:

select

id

from

t

where

namelike'abc%'

select

id

from

t

where

createdate>='2005-11-30'

and

createdate<'2005-12-1'

 

10.不要在where子句中的“=左”边进行函数、算术运算或其他表达式运算,否则系统将可

 

能无法正确使用索引。

 

11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一

 

个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

 

12.不要写一些没有意义的查询,如需要生成一个空表结构:

 

selectcol1,col2into#tfromtwhere1=0

 

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

 

createtable#t(...)

 

13.很多时候用exists代替in是一个好的选择:

 

selectnumfromawherenumin(selectnumfromb)

 

用下面的语句替换:

 

selectnumfromawhereexists(select1frombwherenum=a.num)

 

14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大

 

量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎

 

各一半,那么即使在sex上建了索引也对查询效率起不了作用。

 

15.索引并不是越多越好,索引固然可以提高相应的select的效率,但同时也降低了inser

 

t及update的效率,因为insert或update时有可能会重建索引,所以怎样建索引需要

 

慎重考虑,视具体情况而定。

一个表的索引数最好不要超过6个,若太多则应考虑一些不

 

常使用到的列上建的索引是否有必要。

 

16.应尽可能的避免更新clustered索引数据列,因为clustered索引数据列的顺序就是表

 

记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资

 

源。

若应用系统需要频繁更新clustered索引数据列,那么需要考虑是否应将该索引建为

 

clustered索引。

 

17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。

这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。

 

18.尽可能的使用varchar/nvarchar代替char/nchar,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。

 

19.任何地方都不要使用select*fromt,用具体的字段列表代替“*,”不要返回用不到的

 

任何字段。

 

20.尽量使用表变量来代替临时表。

如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

 

21.避免频繁创建和删除临时表,以减少系统表资源的消耗。

 

22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。

但是,对于一次性事件,最好使用导出表。

 

23.在新建临时表时,如果一次性插入数据量很大,那么可以使用selectinto代替createtable,避免造成大量log,以提高速度;如果数据量不大,为了缓和系统表的资源,应先

 

createtable,然后insert。

 

24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先truncatet

 

able,然后droptable,这样可以避免系统表的较长时间锁定。

 

25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应

 

该考虑改写。

 

26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。

 

27.与临时表一样,游标并不是不可使用。

对小型数据集使用FAST_FORWARD游标通常

 

要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。

在结果集中包

 

括“合计”的例程通常要比使用游标执行的速度快。

如果开发时间允许,基于游标的方法和基

 

于集的方法都可以尝试一下,看哪一种方法的效果更好。

 

28.在所有的存储过程和触发器的开始处设置SETNOCOUNTON,在结束时设置SET

 

NOCOUNTOFF。

无需在执行存储过程和触发器的每个语句后向客户端发送DONE_IN_

 

PROC消息。

 

29.尽量避免大事务操作,提高系统并发能力。

 

30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

精妙的"SQL"语句:

 

◆复制表(只复制结构,源表名:

a新表名:

b)

 

SQL:

select*intobfromawhere1<>1

 

◆拷贝表(拷贝数据,源表名:

a目标表名:

b)

 

SQL:

insertintob(a,b,c)selectd,e,ffromb;

 

◆显示文章、提交人和最后回复时间

SQL:

select

a.title,a.username,b.adddate

fromtable

a,

(select

max(adddate)

adddate

from

table

wheretable.title=a.title)

b

◆说明:

外连接查询

(表名1:

a

表名2:

b)

SQL:

select

a.a,a.b,a.c,b.c,

b.d,

b.ffromaLEFT

OUTJOIN

bONa.a=

b.c

◆日程安排提前五分钟提醒

SQL:

select

*from

日程安排

where

datediff('minute',f

开始时间,getdate())>5

 

◆两张关联表,删除主表中已经在副表中没有的信息

 

SQL:

 

delete

frominfo

wherenot

exists

(select

*

from

infobz

where

info.infid=infobz.infid

◆说明:

SQL:

SELECTA.NUM,A.NAME,B.UPD_DATE,

B.PREV_UPD_DATE

FROM

TABLE1,(SELECT

X.NUM,

X.UPD_DATE,Y.UPD_DATE

PREV_UPD_DATE

FROM

(SELECT

NUM,

UPD_DATE,INBOUND_QTY,

STOCK_ONHAND

FROM

TABLE2

WHERETO_CHAR(UPD_DATE,

'YYYY/MM')

=TO_CHAR(SYSDATE,

'YYYY/MM'))

X,

(SELECT

NUM,

UPD_DATE,STOCK_ONHAND

FROMTABLE2

WHERETO_CHAR(UPD_DATE,'YYYY/MM')

=TO_CHAR(TO_DATE

(TO_CHAR(SYSDATE,

'YYYY/MM')

&brVBar;|

'/01','

YYYY/MM/DD')

-1,'YYYY/MM'))Y,

WHERE

X.NUM=Y.NUM

(+)ANDX.INBOUND_QTY

+NVL(Y.STOCK_ONHAND,0)

<>

X.STOCK_ONHAND

)BWHERE

A.NUM

=B.NUM

◆说明:

 

SQL:

 

select*fromstudentinfowherenotexists(select*fromstudentwhere

 

studentinfo.id=student.id)and系名称='"&strdepartmentname&"'and专业名称

 

='"&strprofessionname&"'orderby性别,生源地,高考总成绩。

 

如何在SQLServer数据库中成批导入数据

 

在软件项目实施的时候,数据导入一直是项目人员比较头疼的问题。

其实,在sqlserver中集成了很多成批导入数据的方法。

有些项目实施顾问头疼的问题,在我们数据库管理员眼中,是小菜一碟。

现在的重点就是,如何让用户了解这些方法,让数据导入变得轻松一些。

 

第一种方法:

使用SelectInto语句

 

若企业数据库都采用的是SQLServer数据库的话,则可以利用SelectInto语句来实现数据的导入。

SelectInto语句,他的作用就是把数据从另外一个数据库中查询出来,然后加入到某个用户指定的表中。

 

在使用这条语句的时候,需要注意几个方面的内容。

 

一是需要在目的数据库中先建立相关的表。

如想把进销存系统数据库(SQLServer)中的

 

产品信息表(Product)导入到ERP系统中的产品信息表(M_Product)中。

则前期是在ERP系

 

统的数据库中已经建立了这张产品信息表。

 

二是这种方法只复制表中的数据,而不复制表中的索引。

如在进销存系统数据中的产品

 

信息表中,在产品编号、产品种类等字段上建立了索引。

则利用SelectInto语句把数据复

 

制到ERP系统的表中的时候,只是复制了数据内容的本身,而不会复制索引等信息。

 

三是这条语句使用具有局限性。

一般情况下,这只能够在SQLServer数据库中采用。

不过,对于SQLServer不同版本的数据库,如2008或者2003,还都是兼容的。

若需要导入的对象数据库不是SQLServer的,则需要采用其他的方法。

 

四是采用这条语句的话,在目的表中必须不存在数据。

否则的话,目的表中的数据会被

 

清除。

也就是说,这个语句不支持表与表数据的合并。

在SQLServer中,有一条类似的语

 

句,可以实现这个功能。

这条语句就是:

InsertInto。

他的作用就是把另外一张表中的数据

 

插入到当前表中。

若用户想要的时表与表数据的合并,则可以采用这条语句。

两者不能够混

 

淆使用,否则的话,很容易导致数据的丢失。

 

五是以上两条语句都支持兼容的不同类型的数据类型。

 

型是整数型,但是在目的表中这个字段的数据类型则是浮点型,

 

就兼容的,则在导入的时候,数据库是允许的。

 

如在原标中,某个字段的数据类

 

只要这个两个数据类型本来

 

第二种方法:

利用Excel等中间工具进行控制

 

虽然第一种方法操作起来比较简单,但是其也有一些缺点。

如他只支持同一种类型的数

 

据库;不能够对数据进行过多的干预等等。

一般情况下,若用户原数据准确度比较高,不需

 

要过多的修改就可以直接拿来用的话,则笔者就已采用第一种方式。

 

但是,若在原数据库中,数据的准确度不是很高,又或者,有很多数据是报废的。

总之,

 

需要对原数据库的数据进行整理,才能够使用的情况,笔者不建议先导入进去,再进行更改。

 

笔者在遇到这种情况时,喜欢利用Excle作为中间工具。

也就是说,先把数据中原数据库中

 

导到Excle中。

有些数据库,如Oracle数据库,他不支持Excle格式。

但是,我们可以把

 

它导为CSV格式的文件。

这种文件Excle也可以打得开。

 

然后,再在Excle中,对记录进行修改。

由于Excle是一个很强的表格处理软件,所以,

 

其数据修改,要比在数据库中直接修改来得方便,来得简单。

如可以利用按时间排序等功能,

 

把一些长久不用的记录清楚掉。

也可以利用替换等功能,把一些不规范的字符更改掉。

 

原来在数据库中比较复杂的任务,在Excle等工具中都可以轻松的完成。

 

这些

 

等到表中的内容修改无误后,数据库管理员就可以把Excle表格中的文件直接导入到

 

QLServer数据库中。

由于SQLServer与Excel是同一个父母生的,所以,他们之间的兼

 

S

容性很好。

SqlServer中提供了直接从

Excel

文件中导入数据的工具。

 

虽然这要借助中间工具导入数据,但是,因为其处理起来方便、直观,所以,笔者在大

 

部分时候都是采用这种方式。

 

第三种方式:

使用数据转换服务导入数据

 

数据转换服务是SQLServer数据库中提供的一个非常强大的工具。

数据转换功能有一个图形用户接口,用户可以在图形界面中导入数据,编辑。

 

在SQLServer中,并对数据进行相应的

 

另外,数据转换服务还支持COM组件的编程接口。

这也就是说,在前台应用程序开发的时候,可以直接调用数据转换服务。

让用户通过前台应用系统,而不用在后台数据库系统进行任何的操作,就可以把数据导入数据库系统中去。

在前台对数据库系统进行导入,有一个明显的好处,就可以预先对数据的合法性进行检查。

如可以利用VB等脚本语言对数据进行检验、净化和一定的转换,以符合目的数据库的需要。

 

如在员工信息表中的婚姻状况字段,在Oracle数据库系统中,可能是用0或者1来表示婚姻状况。

0表示未婚,1表示已婚。

而在SQLServer数据库中,则利用Y或者N来表示婚姻状况。

Y表示已婚,N表示未婚。

在导入数据的时候,若直接把Oracle数据库表中的数据导入到SQLServer数据库中,因为婚姻状况这个字段存储的内容类型不同,所以,

 

不能够直接导。

遇到这种情况的话,则就可以在导入数据之前,先利用脚本语言对数据类型

 

进行验证。

若不符合要求的,则可以通过脚本语言对数据进行一定的转换,把把1转换为Y等等。

 

0转换为

 

N,

 

所以,有时候程序员在开发前台应用程序的时候,若要开发数据导入功能的话,我们都

 

是建议采用这个数据转换服务。

不但有现成的接口,而且,还可以对数据进行验证与一定程

 

度的转换。

另外,数据转换服务的数据导入效率非常的高。

即使通过前台程序调用,其性能

 

也比其他方法在同等条件下,要高一个档次。

而且,随着数据量的增加,数据转换服务的优

 

势会越来越明显。

 

不过,在前台应用程序调用数据转换服务的时候,需要注意。

数据转换服务提供的CO

 

M接口比较复杂,所以,前台程序调用数据转换服务的代码也比较复杂。

若再加上一些脚

 

本语言的话,可能处理起来更加的繁琐。

故一般只有在大型系统上才会用到这个接口。

 

据不多,否则不需要复杂验证与转换的话,利用这个接口是大刀小用,得不偿失。

 

若数

 

第四种方式:

异构数据库之间的导入导出

 

虽然第二种、第三种方式都可以完成异构数据库之间数据的导入导出作业。

不过,在S

 

QLServer中,还提供了另外一种解决方案。

即直接在SQLServer数据库中连接到其他类

 

型的数据库上,然后采用SelectInto等语句实现数据的导入作业。

 

在SQLServer中,提供了两个函数可以帮助我们实现对非SQLServer数据库的连接。

这两个函数分别为Opendatesource与Openrowset。

他们的功能基本相同,只是在细节上有所差异。

 

如Opendatesource这个函数至能够打开源数据库的表和视图,而不能够对其进行过

 

滤。

若用户只想把源表中的部分数据导入到SQLServer数据库的表中,则不能对源表直接进行过滤。

过滤的动作需要在SQLServer数据库中进行。

而Openrowset这个函数,可以

 

在打开对方数据库的表或者视图的时候,直接利用Where等条件限制语句对记录进新过滤。

 

为此,在实际应用中,还是Openrowset这个函数使用的频率比较高。

 

不过由于其需要用户写复杂的参数,而且,又不能够提供复杂的数据验证功能,所以在

 

实际工作中用的并不是很多。

在一些小的应用系统中,偶尔还可以见到其的踪影。

在一些大

 

的成熟的商业软件中,很少采用这种方式,对数据进行导入。

 

有时候,选择多了,用户反而不知道如何下手。

笔者平时最喜欢采用的是第二种处理方

 

式。

他比较直观,而且,可以对数据进行成批的更改与整理。

但是,其缺陷就是效率比较低,

 

特别是Excle软件对于处理大量记录的时候,速度比较慢。

若这种方式行不通的话,则笔者

 

比较倾向于采用数据转换的处理方式。

这个操作起来虽然比较复杂,但是,其可以提供比较

 

复杂的验证,而且可以在图形化的界面中对数据进行修改,同时效率也比较高。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工程科技 > 能源化工

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1