关于SQL语句执行效率的研究
2014-11-05董非
摘 要
在针对数据库操作的应用程序设计中,SQL语句的编写也会影响到程序响应速度和用户的体验度,尤其是数据量较大的应用。本文通过对SQL语句的执行顺序进行分析,探讨和分析提高SQL语句效率的方法以及SQL语句的优化方式。
【关键词】SQL语句 执行效率 方法
随着计算机技术的发展,各种各样的应用软件进入到我们的生活中。大多数软件在与用户交互时都会进行数据的查询、存储等操作。科学合理的数据库查询语句可以提高数据库的查询性能,随之将会提高软件的响应速度和用户体验度,在数据库应用系统中起着关键的作用。
1 SQL语句
SQL语句是STRUCTURED QUERY LAN -GUAGE的缩写,即结构化查询语言。在1986年10月通过了美国国家标准局的数据库语言美国标准,经过多年的扩展和标准化,在各种不同的数据库中已经基本达到通用。可以独立于数据库和计算机软硬件。
我们这里讨论的是结构化查询语言的一部分,叫做数据查询语句(Data Query Language)。数据查询语句也称为数据检索语句,用以从数据库表中获得需要的数据,返回给应用程序。数据查询语句中最常用的保留字是SELECT,其他的还有WHERE,ORDER BY,GROUP BY和HAVING。这些DQL保留字与其他类型的SQL语句一起使用。比如:
SELECT id,name,age,address FROM students WHERE name=rose ORDER BY age
这条查询语句的意思是:从students学生表中查询出所有名叫rose的的学生,并且返回的结果集按照age年龄字段顺序排列。
2 SQL语句的效率
SQL作为查询语言有灵活的编写方式,语句的写法完全取决于编写者。当数据库收到一个查询语句时,首先完成语法解释,然后再进行编译,生成可以执行的“执行计划(execution plan)”。在语句编译过程中,数据库会根据指令内容和估算可能的执行计划,再根据每个计划的运行成本选择一个数据库认为成本最低的计划执行。数据库会把这些执行计划缓存在内存中,被称作执行缓存(plan cache)。以后遇到同样的语句时,数据库就可以使用同样的执行计划,而不用再次编译。
程序员在编写SQL语句时往往会陷入一种误区,那就是关注与SQL语句的执行结果而忽略了不同实现方法之间存在的性能的差异。对于相同的数据库结构来说,执行计划的成本消耗,完全取决于SQL语句的编写方式。这种实现方式的差异在大行或复杂的数据库中表现的更为明显。
经过实践发现,执行成本较高的SQL语句除了数据库设计不合理以外,不恰当的连接语句和不可优化的条件语句也是其中的主要原因。比如一条包含子查询的语句:
SELECT dd FROM A WHERE aa IN (SELECT aa FROM B)
在连接子查询中,效率的高低与使用IN还是用EXISTS有关。EXISTS会针对子查询表使用索引功能,IN会针对主表动用索引功能。可以确定,当主表数据量大时采用IN效率高,当子查询数据量大是采用EXISTS效率高。因此,SQL语句的执行效率和编写方法有直接关系。
下面简单说一下SQL语句的执行顺序:
FROM子句标识了需要查询的表,如果指定了表操作,会从左到右的处理,每一个基于一个或者两个表的表操作都会返回一个输出表。左边表的输出结果会作为下一个表操作的输入结果。
对于外连接(LEFT,RIGHT, or FULL),可以标记一个或者两个表作为保留表。作为保留表意味着这个表里面的所有列都被返回,即使它里面的数据不满足ON子句的过滤条件。 LEFT OUTER JOIN 把左边的表标记为保留表,RIGHT OUTER JOIN把右边的表作为保留表,FULL OUTER JOIN把两个表都标记为保留表。
WHERE过滤被应用到前一步生成的临时表中,根据WHERE过滤条件生成临时表。关于ON 和 WHERE 的区别需要在这里说明一下,ON 和WHERE 的主要区别在于 ON 是在添加外部列之前进行过滤,WHERE 是在之后,如果你不需要添加外部列,那么这两个过滤是相同的。
3 提高SQL语句效率的方法
为了提升SQL语句的执行效率,可以采用以下办法实现:
(1)在表中建立索引,在数据库中使用索引能够大大提高检索性能,这一点是非常明显的。用的索引越多,从数据库系统中得到数据的速度就越快。尽量在查询中明确需要的字段,减少使用类似于“SELECT name FROM TABLE1”这种查询语句。
(2)同时还需要注意一点就是要有效使用索引,并不是越多越好。索引固然可以提高查询的效率,但同时也降低了插入和更新语句的效率,因为在数据插入或更新时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
(3)在WHERE子句中尽量避免使用“!=、<、>”等操作符号,否则数据库会进行全表检索。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。比如:
SELECT name FROM TABLE1 WHERE ID=‘1
可以改为强制使用索引方式
SELECT name FROM TABLE1 WITH(INDEX(索引名)) WHERE ID=‘1
(4)如果有NOT IN、NOT EXISTS的子查询可以用LEFT JOIN代替。使用前者时,数据库会逐条对比,对比数量等于笛卡尔积,而使用LEFT JOIN会大大减少数据库的工作量。endprint
(5)在数据库检索时,尽量使用数字型字段作为条件,这将大大提高查询和连接的性能,减少存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
(6)尽量不要对索引字段进行运算或格式化等操作,比如:
SELECT ID FROM TWHERE NUM/2=100
应该改为
SELECT ID FROM TWHERE NUM=100*2
(7)在使用IN的时候,后面值的列表中,将出现最频繁的值放在最前面,出现得最少的放在最后面,这样可以减少判断的次数。
(8)HAVING、WHERE和ON这三个都可以加在条件子句中,在使用的时候需要注意一下它们的执行顺序,ON是在查询中最先执行的语句,接着是WHERE,HAVING最后被执行。在正常情况下,这三个条件的先后顺序不会影响到最终的查询结果。但从效率方面考虑,ON应该是最快的,ON是先把不符合条件的记录过滤后才进行统计,它就可以减少中间运算要处理的数据。接着是WHERE,它会比HAVING快点的,因为它过滤数据后才进行求和运算,HAVING相比之下是最慢的。
单表查询统计的情况下,如果查询条件中没有涉及到需要计算字段,那么HAVING和WHERE的查询结果是一样的。但是如果查询结果涉及到计算的字段以后,那就表明在还没有计算之前,这个字段的值是不能确定的,而HAVING正是在计算后才起作用,主要是用来弥补WHERE在分组数据判断时的不足[3]。比如:
SELECT class,SUM(studentNO) FROM students GROUP BY class HAVING SUM(studentNO)>60
这条语句是查询出人数大于60人的班级,在这里我们就不能用WHERE来替换HAVING,因为WHERE的作用时间是在计算之前就完成的,而计算之前的表中就不存在符合条件的记录,那么就只能用HAVING来进行筛选。
在多表联接查询时ON比WHERE更早起作用,这是因为系统首先根据各个表之间的联接条件,把多个表合成一个临时表后,再由WHERE进行过滤,然后再计算,计算完后再由HAVING进行过滤。由此可见,要想过滤条件起到正确的作用,首先要明白这个条件应该在什么时候起作用,然后再决定放在那里。
4 结语
总之,通过对数据库编译顺序的学习可以了解相似的保留字编译成执行代码的差异,用以指导SQL语句的实现方式,提高语句执行效率。但是对于大型数据库来说,要实现良好的性能还需要在设计和实现上使用更多的技巧和优化。
参考文献
[1]钱文波,谢金宝.SQL Server数据库性能优化技术[J].微型机与应用,1999.
[2]吴险峰.SQLServer环境下的SQL优化方法探讨[J].电脑知识与技术,2008.
[3]李海翔.数据库查询优化器的艺术:原理解析与SQL性能优化[M].北京:机械工业出版社,2014.
作者简介
董非(1981-),男,湖北省十堰市人。硕士学位。现供职于陕西瑞珂工程咨询有限责任公司。中级职称。研究方向为计算机技术。
作者单位
陕西瑞珂工程咨询有限责任公司 陕西省西安市 710065endprint