menu

开发进行时...

crazy coder

Avatar

优化

包含SELECT语句的查询

如果没有正确地编写和组织SELECT语句,那么,这个SELECT语句的执行可能会占用很长的时间。因为它们可能在结构上有着极大的不同,所以在编写这些类型的SQL语句时,应当记住以下各点:
1、当创建一个选择列表时,仅仅指定那些必要的列(即只指定在选择列表中需要的那些列)。换句话说,如果你不需要那些数据,那么就不要去检索它。尽管用星号指定所有列可能更简单,但会产生不需要的处理并返回不想要的列。从而对应用程序的整体性能产生负面的影响。
2、通过使用谓词(=,<,>.BETWEEN,NOT,IN,LIKE etc)将结果集限制为只包含必要的那些行,以限制选择的行数。如果发现应用程序经常使用这些谓词来查询所需要的数据列,那么可以考虑在这个列上创建索引来改善性能。
3、尽可能避免数据类型的转换。当比较值时,使用相同的数据类型通常是更有效的。要尽量多的使用日期和数字的数据类型,而尽可能少使用字符数据类型。即使用下列数据类型:
1)非可变字符,用于较短的列。
2)整数而不是浮点数或小数。
3)日期时间面不是字符。
3)数字而不是字符。
4、当使用带DISTINCT、ORDER BY和GROUP BY子句的SELECT语句时,要指定索引列。通过指定索引列,将极大地减少处理这一类语句所需要的时间。当然,也应该尽可能地为这些列创建唯一索引。
5、如果在你的数据集中所需要的行数大大少于查询可能返回总行数,当对SELECT语句指定OPTIMIZE FOR子句。此子句会影响存取方案的选择以及在通信缓冲区中央分块的行。
6、当创建用来更新数据的游标时,请指定FOR UPDATE OF子句来改善性能,因为它使数据库管理程序在一开始就可选择更适合的锁定级别,从而避免潜在的死锁、锁定升级和锁定转换。
7、要检查一个大型表中是否存在一些行时,不要使用“SELECT COUNT(*)”语句。除非知道该表将很小。建议改试单行选择。因此,为了检查某一个表中的行是否存在,可执行一个单行选择(SELECT INTO)。并从返回的SQL CODE值来确定数据存在与否。
8、对于一个长的或复杂的查询,应该尽可能地使用动态SQL和参数标记。这样做将允许优化器能够基于参数标记的值,而不是未知的宿主变量的值,来选择一条存取路径。采用这种基于特定值的访问计划可以显著地提高性能。
9、当要检索的行数很小时,不需要指定OPTIMIZE FOR k ROWS 子句和FETCH FIRST n ROWS ONLY子句。然而,如果n值很大并且您想要通过快速获取前k行(而可能延迟后续k行)进行优化,则同时指定两个子句。根据n和k中的较小者来确定通信缓冲区的大小。
SELECT EMPNAME,SALARY FROM EMPLOYEE
ORDER BY SALARY DESC
FETCH FIRST 100 ROWS ONLY
OPTIMIZE FOR 20 ROWS
10、指定FOR READ ONLY(或FOR FETCH ONLY)子句可改善性能,因为允许您的查询利用行分块。它也可改善数据并行性,因为永远不会对指定了此子句的查询所检索到的行保持互斥锁。它也允许进行附加的查询重写。指定FOR READ ONLY(或FOR FETCH ONLY)子句,同时指定BLOCKING ALL BIND,可改善联合体系中对别名查询的性能。
11、包含子句或操作(如DISTINCT或ORDER BY)的SQL语句要求对数据排序,才能执行该操作。如果您要降低使用排序操作的可能性,当不需要这些子句时,不要指定它们。
12、如果更新活动较少且您的表较大,则在频繁用作谓词的列上定义索引。
13、如果同一列出现在多个谓词子句中,则考虑使用IN列表。
14、对于配合主变量使用的大型IN列表,套入主变量子集可能会改进性能。

存取两个或更多个的表的查询

考虑尽可能的使用连接而不是子查询包含其他SELECT语句的SELECT SQL语句。
1、连接表时使用连接谓词(连接谓词是来自一个连接中不同的表的两个列之间的比较)。如果可能的话,避免在连接谓词中使用表达式或OR子句。对于这种情况,DB2数据库管理器不能使用某种连接技术,因此可能无法选择最有效的连接方法。
2、如果可能的话,尽量使用连接替代相关子查询。连接与相关子查询相比,处理连接通常只需要更少的时间和资源。这是因为相关子查询必须对外部查询的每一行进行重新评诂。
3、如果可能的话,尽量使用连接替代在IN谓词之前的非相关子查询。尽管一个非相关子查询仅仅被评估一次,但是在外部的SELECT语句所引用的每一行中,和IN谓词一起使用的数据列将与子查询的输出数据(一组值)相比较。如果我们使用了大型表,这个比较过程会占相当长的时间。
4、如果可能的话,尽量在被连接使用的每张表的列上创建一个索引。如果在连接谓词所引用的每一列上定义相关的索引,那么可以更有效地处理连接。这也会改善UPDATE和DELETE语句的性能,它们包含存取几个表的SELECT语句。
5、如果可能的话,确保在一个分区数据库环境中按连接列来分区连接的表。


创建索引的准则

取决于实际存储的数据和将来要怎样使用这些数据。
1、如果经常在包含若干数据页的表上执行查询(数据页是表或索引中的存储单位,通常为4KB大小),那么可以在查询所涉及的列上创建一个索引。
2、如果频繁地在某张表上搜索特定值,就可以在那个表中的一个或多个列上创建索引。
3、如果计划连接表,则在被连接使用的列上创建一个索引。
4、如果频繁地执行包含WHERE子句的查询和事务,那么,可以在WHERE子句所用的那些列上创建索引。请看以下的WHERE子句:
WHERE WORDEPT='A01' OR WORKDEPT='E21'
根据WORKDEPT创建索引以改进性能。
5、如果要经常执行包含ORDER BY、DISTINCT或GROUP BY子句的查询和事务,在这些子句所指定的一列或多列上创建索引。请看以下示例使用DISTINCT子句:
SELECT DISTINCT WORKDEPT
FROM EMPLOYEE
数据库管理器可使用定义为升序或降序的、基于WORKDEPT的索引来消除重复值。这同一个索引也可用于GROUP BY子句中,以将值分组,如以下示例所示:
SELECT WORKDEPT,AVERAGE(SALARY)
FROM EMPLOYEE
GROUP BY WORKDEPT
6、要尽可能地只定义主键和唯一键。唯一索引能够帮助优化器避免执行某些特定的操作(如排序)。
7、避免创建的索引是这些列上其他索引关键字的部分关键字。例如,如果创建了一个使用A、B、C和D列的一个索引,则在列A、B和D上创建第二个索引的用处不大。
8、在外部关键字上创建索引可改进在父表上执行删除和更新操作的性能。
9、在创建多列索引时,如果第一个关键字列有多项选择,则首先选择频繁用“=”谓词指定的那一列,或指定具有最多相异值的那些列。
10、无论应用在何处,都使用CREATE UNIQUE INDEX语句定义主关键和唯一关键字。
11、使用include列来定义唯一索引可改善数据检索的性能。如果列满足下列条件,则适合作为惟一索引的INCLUDE列:
1)被频繁存取,因此可从纯索引存取中受益。
2)不需要用来限制索引扫描的范围。
3)不影响索引关键字的排序或唯一性。
12、使用索引可优化对含有较多数据页的表的频繁查询,数据页由SYSCAT.TABLES目录视图中的NPAGES列确定:
1)根据连接表时要使用的任何一列来创建索引。
2)根据将用于定期搜索特定值的任何列来创建索引。
13、决定对关键字使用升序还是降序,这取决于该次序是主要使用的还是请求的。仅当在CREATE INDEX语句中指定了ALLOW REVERSE SCANS参数时,才能以相反方向搜索那些值。尽管可按正反两个方向扫描索引,但索引的正向扫描(即创建索引时指定的次序)比索引的反向表表现略好些。
14、对将频繁用于数据排序的列使用索引。
15、在所有列中任意选择来创建索引,不仅消耗大量磁盘空间,而且导致准备时间过长。对于复杂的查询更是如此,对复杂的查询使用具有动态规划连接枚举的优化级别。
16、下面提供了一个经验法则,用来确定将为表定义的索引的典型数目。此数目由数据库主要使用的索引来确定的:
1)对于联机事务处理(OLTP)环境,应只有一个或两个索引。
2)对于查询(只读)环境,可有五个以上的索引。
3)对于混合查询/OLTP环境,可有两个至五个索引。
17、考虑定义一个群集索引,以帮助新插入的行根据该索引进行群集。群集索引可以尽量避免重组表。注意:当定义了一个群集索引时,应装入该表,且在每个数据页上保留空闲空间,以允许在这些页上进行插入。(通过在ALTER TABLE语句上使用PCTFREE关键字,或使用LOAD命令的pagefreespace MODIFIED BY子句,来保留空闲空间。)
18、创建索引时考虑使用PCTFREE关键字。PCTFREE在索引页上保留空间,以便将来对索引进行更新。这可能减少页分割的频率并提高性能。
19、创建索引时考虑使用MINPCTUSED选项。MINPCTUSED指定索引叶页中已使用空间的最小阈值,并启用联机索引重组。这可能减少对数据和索引脱机重组的需要。
注意:已说明临时表不支持索引。

以下是创建索引以改善性能的典型情况:
1、可创建索引来命名一个语句中的每一列。当用此方式指定索引时,生成的纯索引存取表示通过避免表存取可更有效地检索数据。
例如,假定发出以下的SQL语句:
SELECT LASTNAME FROM EMPLOYEE WHERE WORKDEPT IN('A00','D11','D21')
如果为EMPLOYEE表的WORKDEPT和LASTNAME列定义了索引,则通过扫描索引而不扫描整个表可能会更有效地处理该语句。注意,因为该谓词基于WORKDEPT,因此此列应是该索引的第一列。
2、索引上的Iclude列是改进对表使用索引的另一种方法。使用上述示例,可将唯一索引定义为:CREATE UNIQE INDEX x ON employee(workdept) INCLUDE(lastname)指定lastname为include列而不是索引关键字的一部分,意味着lastname只存储在索引的叶页上。

优化索引性能

可以将索引存储在另外的表空间中,与其他表数据分开存储。
在(order by,distinct,group by etc)一些查询中索引无效的情况可能是:
1)索引分组级别较低(查看SYSCAT.INDEXES的CLUSTERRATIO和CLUSTERFACTOR列)。
2)表很小,以至于可以在内存中扫描该表并对回答集排序。
3)对存取该表有多个索引可供选择。

建议在创建群集索引后,执行REORG或排序,然后执行LOAD。通常,一个表只能在一个索引上群集。您的表和索引应该按该表的群集索引的顺序来构建。

评论已关闭