(转摘)_《数据库设计入门经典》:构建快速执行的数据库模型_8.2 编写高效查询
8.2 编写高效查询
高效SQL代码主要是指使用SELECT命令的高效查询。SELECT命令允许使用WHERE子句来减少读取的数据量。WHERE子句用于返回(或不返回)特定的记录。UPDATE命令和DELETE命令同样也可以有WHERE子句,因此通过WHERE子句的使用,减少数据访问量也能提高这两个命令的性能。
提示:
向数据库添加记录的INSERT命令的性能调整通常是开发人员和管理员的工作。这是因为终端用户通常会使用应用程序来向数据库添加数据。元数据修改命令,如CREATE
TABLE命令和ALTER TABLE命令则大部分是数据库管理的工作。因此INSERT命令和元数据命令与本文无关。
在OLTP数据库中,小事务与高并发性是最重要的两个方面。SQL代码的准确性和索引匹配也相当关键。在数据仓库中则普遍使用大型查询和批量更新。因此在数据仓库中,大型复杂查询要对尽可能少的表进行,以便减少连接查询中表的数量。对OLTP数据库和数据仓库数据库而言,在查询中同时连接过多表对查询性能的影响最大。数据仓库还由于巨大的数据量而使问题进一步恶化。
在调整SQL代码性能时,有如下一些常用经验:
● 数据库模型设计支持SQL代码——
SQL代码的质量完全依赖于数据库模型设计的质量,不但与规范化和非规范化的正确性有关,而且与表结构的恰当与否有关。例如,由于OLTP数据库中常见的过度规范化、粒度化和深范式表完全不适合数据仓库所需的跨越多表的超大型事务,因此数据仓库需要数据仓库的数据库模型设计。
● KISS法则(Keep It Simple and Stupid,保持简洁通俗)——
分割为简单(最好独立)块的应用程序代码总是更容易领会,因此简单子句的简单SQL命令也更容易编写,也容易调整。越长、越复杂的查询就越难编写,也就越难得出正确的结果。性能调整只是一个附加步骤。如果因为某些笨拙的查询运行过慢而需要进行调整,这种情况实际上是不正确的。只有保持查询的简洁,才有可能更快速地运行查询。如果问题在于太过复杂,那么首先应该进行简化。至少,保持简洁能够帮助您确切得知查询的进度,不会让您总是盯着一行行毫无意义的SQL代码而头疼。
● 优秀的表结构便于构造SQL代码——
注意与SQL代码构造和编写方法或形式相关的所有细节,当然数据库模型除外。在理想表结构中,应该可以从表结构或表结构子集直接编写SQL代码,而不用绕弯。因此SQL代码的编写不应该有困难。您也不应该经常觉得(挑剔怀疑或预感到)表结构有所不妥。因此数据库模型的结构应该便于构造SQL代码。毕竟,应用程序是由SQL代码支持的。不要忘记SQL代码对数据库表结构的依赖性。如果应用程序需求与数据库结构之间出现不匹配,那么可能数据库模型有所错误。在这种情况下对SQL代码进行性能调整会出现严重的问题。
● 分解成最小块——
分解SQL代码命令的结构,例如查询和DML命令(INSERT命令、UPDATE命令和DELETE命令)。但不要分解非查询类和非DML类命令。例如,不要让访问数据库的每一个SQL代码片断在执行时不断连接数据库并断开数据库。可以让每个用户连接一段时间,也可以在会话开始到结束的过程中保持连接。另一方面,尽量多使用子查询来简化代码的编写。稍后仍可以将子查询合并到父查询中。
注意:
最重要的是,SQL代码及其所能执行的理想速度完全取决于数据库模型的底层结构。查询基本上建立在数据库表以及表间关系上。
构造SQL代码的最基本要素时,可以使用一组特殊的方法来保证优秀的处理性能。查询性能调整的最基本规则有很多个重要方面。下面列出了底层数据库模型结构对各方面性能因素的影响:
● SELECT命令——
关系到SELECT命令中用到多少表。该因素对查询性能有非常显著的影响。数据库模型的粒度越高,需要同时检索的表就越多。检索字段的方式同样也会影响性能,但连接中的表数更为重要,尤其是对较大的数据库而言。
● WHERE子句——
关系到记录筛选的方式。使用比较条件时要求对记录使用WHERE子句,例如检索作者姓名中有元音“a”的记录。比较条件是决定WHERE子句构造的主要因素。有很多种不同的比较条件。查询中筛选记录的方式能够影响查询执行的方式,因此对性能也有很显著的影响。索引对执行WHERE子句筛选有非常大的影响。
● GROUP BY子句—— GROUP
BY子句把从数据库检索的记录聚合成记录的汇总分组。在一对多表间关系上作直接映射,能够很好地实现分组。数据仓库中常用物化视图对GROUP
BY子句聚合进行预计算和预存储。
● 连接——
连接查询会从多个表中检索记录,并根据表间字段值关系来连接这些表。一般来说,表间关系建立在两个表之间主键和外键的参照完整性上。提高查询执行速度最重要的因素可能是表的连接、以及连接中的表数(参见之前讨论内容)。在考虑数据库模型设计时,数据库模型的粒度越高(表越多,就会分解出越多小块),连接查询中表的数量就越多。这一点对数据仓库尤为重要,因为数据仓库往往包含庞大的数据量;不过,即使在OLTP数据库中,由于大量的小型事务,10个以上表的大型连接对性能的影响相当于数据仓库连接查询中两个大型表的影响。
提示:
连接对性能非常重要。如果数据库模型中存在过多细小的表(粒度过高或过度规范化),那么该数据库模型设计会对连接查询的性能产生深远的影响。
高效SQL代码主要是指使用SELECT命令的高效查询。SELECT命令允许使用WHERE子句来减少读取的数据量。WHERE子句用于返回(或不返回)特定的记录。UPDATE命令和DELETE命令同样也可以有WHERE子句,因此通过WHERE子句的使用,减少数据访问量也能提高这两个命令的性能。
提示:
向数据库添加记录的INSERT命令的性能调整通常是开发人员和管理员的工作。这是因为终端用户通常会使用应用程序来向数据库添加数据。元数据修改命令,如CREATE
TABLE命令和ALTER TABLE命令则大部分是数据库管理的工作。因此INSERT命令和元数据命令与本文无关。
在OLTP数据库中,小事务与高并发性是最重要的两个方面。SQL代码的准确性和索引匹配也相当关键。在数据仓库中则普遍使用大型查询和批量更新。因此在数据仓库中,大型复杂查询要对尽可能少的表进行,以便减少连接查询中表的数量。对OLTP数据库和数据仓库数据库而言,在查询中同时连接过多表对查询性能的影响最大。数据仓库还由于巨大的数据量而使问题进一步恶化。
在调整SQL代码性能时,有如下一些常用经验:
● 数据库模型设计支持SQL代码——
SQL代码的质量完全依赖于数据库模型设计的质量,不但与规范化和非规范化的正确性有关,而且与表结构的恰当与否有关。例如,由于OLTP数据库中常见的过度规范化、粒度化和深范式表完全不适合数据仓库所需的跨越多表的超大型事务,因此数据仓库需要数据仓库的数据库模型设计。
● KISS法则(Keep It Simple and Stupid,保持简洁通俗)——
分割为简单(最好独立)块的应用程序代码总是更容易领会,因此简单子句的简单SQL命令也更容易编写,也容易调整。越长、越复杂的查询就越难编写,也就越难得出正确的结果。性能调整只是一个附加步骤。如果因为某些笨拙的查询运行过慢而需要进行调整,这种情况实际上是不正确的。只有保持查询的简洁,才有可能更快速地运行查询。如果问题在于太过复杂,那么首先应该进行简化。至少,保持简洁能够帮助您确切得知查询的进度,不会让您总是盯着一行行毫无意义的SQL代码而头疼。
● 优秀的表结构便于构造SQL代码——
注意与SQL代码构造和编写方法或形式相关的所有细节,当然数据库模型除外。在理想表结构中,应该可以从表结构或表结构子集直接编写SQL代码,而不用绕弯。因此SQL代码的编写不应该有困难。您也不应该经常觉得(挑剔怀疑或预感到)表结构有所不妥。因此数据库模型的结构应该便于构造SQL代码。毕竟,应用程序是由SQL代码支持的。不要忘记SQL代码对数据库表结构的依赖性。如果应用程序需求与数据库结构之间出现不匹配,那么可能数据库模型有所错误。在这种情况下对SQL代码进行性能调整会出现严重的问题。
● 分解成最小块——
分解SQL代码命令的结构,例如查询和DML命令(INSERT命令、UPDATE命令和DELETE命令)。但不要分解非查询类和非DML类命令。例如,不要让访问数据库的每一个SQL代码片断在执行时不断连接数据库并断开数据库。可以让每个用户连接一段时间,也可以在会话开始到结束的过程中保持连接。另一方面,尽量多使用子查询来简化代码的编写。稍后仍可以将子查询合并到父查询中。
注意:
最重要的是,SQL代码及其所能执行的理想速度完全取决于数据库模型的底层结构。查询基本上建立在数据库表以及表间关系上。
构造SQL代码的最基本要素时,可以使用一组特殊的方法来保证优秀的处理性能。查询性能调整的最基本规则有很多个重要方面。下面列出了底层数据库模型结构对各方面性能因素的影响:
● SELECT命令——
关系到SELECT命令中用到多少表。该因素对查询性能有非常显著的影响。数据库模型的粒度越高,需要同时检索的表就越多。检索字段的方式同样也会影响性能,但连接中的表数更为重要,尤其是对较大的数据库而言。
● WHERE子句——
关系到记录筛选的方式。使用比较条件时要求对记录使用WHERE子句,例如检索作者姓名中有元音“a”的记录。比较条件是决定WHERE子句构造的主要因素。有很多种不同的比较条件。查询中筛选记录的方式能够影响查询执行的方式,因此对性能也有很显著的影响。索引对执行WHERE子句筛选有非常大的影响。
● GROUP BY子句—— GROUP
BY子句把从数据库检索的记录聚合成记录的汇总分组。在一对多表间关系上作直接映射,能够很好地实现分组。数据仓库中常用物化视图对GROUP
BY子句聚合进行预计算和预存储。
● 连接——
连接查询会从多个表中检索记录,并根据表间字段值关系来连接这些表。一般来说,表间关系建立在两个表之间主键和外键的参照完整性上。提高查询执行速度最重要的因素可能是表的连接、以及连接中的表数(参见之前讨论内容)。在考虑数据库模型设计时,数据库模型的粒度越高(表越多,就会分解出越多小块),连接查询中表的数量就越多。这一点对数据仓库尤为重要,因为数据仓库往往包含庞大的数据量;不过,即使在OLTP数据库中,由于大量的小型事务,10个以上表的大型连接对性能的影响相当于数据仓库连接查询中两个大型表的影响。
提示:
连接对性能非常重要。如果数据库模型中存在过多细小的表(粒度过高或过度规范化),那么该数据库模型设计会对连接查询的性能产生深远的影响。