Answers:
这是我经常给别人询问优化问题的便捷清单。
我们主要使用Sybase,但是大多数建议将全面适用。
例如,SQL Server附带了许多性能监视/调整位,但是如果您没有这样的功能(甚至可能没有),那么我将考虑以下内容...
我看到的问题中有99%是由于在联接中放置太多表引起的。解决此问题的方法是进行一半的连接(使用某些表),并将结果缓存在临时表中。然后在该临时表上进行其余查询的联接。
#temp
表的性能可能比@table
大容量(数千行)的变量好得多。稍微偏离主题,但是如果您可以控制这些问题,那么...
高层次和高影响力。
CREATE INDEX
确保您的WHERE
和JOIN
子句有可用的索引。这将大大加快数据访问速度。
如果您的环境是数据集市或仓库,则几乎所有可能的查询都应包含索引。
在事务性环境中,索引的数量应更少,其定义应更具战略意义,以便索引维护不会拖累资源。(索引维护是指必须更改索引的叶子以反映基础表中的更改,例如INSERT, UPDATE,
and DELETE
操作。)
另外,请注意索引中字段的顺序-字段的选择性越强(基数越高),它应该在索引中越早出现。例如,假设您要查询二手车:
SELECT i.make, i.model, i.price
FROM dbo.inventory i
WHERE i.color = 'red'
AND i.price BETWEEN 15000 AND 18000
价格通常具有较高的基数。可能只有几十种颜色可用,但可能有成千上万种不同的要价。
在这些索引选择中,idx01
提供了满足查询条件的更快路径:
CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)
这是因为满足价格要求的汽车要比颜色选择少,因此查询引擎要分析的数据少得多。
众所周知,我有两个非常相似的索引,只是在字段顺序上有所不同,以加快一个查询(名字,姓氏)和另一个查询(姓氏,名字)的速度。
我最近了解到的一个技巧是,SQL Server可以在更新语句中更新局部变量以及字段。
UPDATE table
SET @variable = column = @variable + otherColumn
或更易读的版本:
UPDATE table
SET
@variable = @variable + otherColumn,
column = @variable
在实现递归计算时,我用它来替换复杂的游标/联接,并且还获得了很多性能。
这里的详细信息和示例代码极大地提高了性能:http : //geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal。 aspx
假设这里使用MySQL,请使用EXPLAIN找出查询的内容,确保尽可能高效地使用索引,并尝试消除文件排序。高性能MySQL:优化,备份,复制和其他功能以及MySQL Performance Blog都是一本关于此主题的好书。
有时,在SQL Server中,如果在where子句中使用OR,它将真正提高性能。而不是使用OR,只需执行两个选择并将它们合并在一起。您可以以1000倍的速度获得相同的结果。
我已经习惯了总是使用绑定变量。如果RDBMS不缓存SQL语句,则绑定变量可能无济于事。但是,如果您不使用绑定变量,则RDBMS将没有机会重用查询执行计划和已解析的SQL语句。节省的费用可能是巨大的:http://www.akadia.com/services/ora_bind_variables.html。我主要使用Oracle,但Microsoft SQL Server的工作方式几乎相同。
以我的经验,如果您不知道是否正在使用绑定变量,则可能不是。如果您的应用程序语言不支持它们,请找到一种支持的语言。有时,您可以通过对查询B使用绑定变量来修复查询A。
之后,我与我们的DBA进行了交谈,以找出导致RDBMS最痛苦的原因。请注意,您不应询问“为什么此查询速度慢?” 这就像要求您的医生将您的阑尾取出。当然,您的查询可能是问题所在,但很可能其他地方出了问题。作为开发人员,我们倾向于考虑代码行。如果线路较慢,请修复该线路。但是RDBMS是一个非常复杂的系统,查询速度慢可能是更大问题的征兆。
太多的SQL调优技巧是狂热的偶像。在大多数情况下,问题与您使用的语法无关或具有最小的关系,因此通常最好使用可以使用的最简洁的语法。然后,您可以开始研究调整数据库的方法(而不是查询)。仅在失败时调整语法。
像任何性能调整一样,请始终收集有意义的统计信息。除非您正在调整用户体验,否则不要使用挂钟时间。取而代之的是看CPU时间,读取的行和从磁盘读取的块之类的事情。人们常常为错误的事情进行优化。
SET NOCOUNT ON
通常,除非实际需要使用,否则我的存储过程通常位于第一行@@ROWCOUNT
。
在SQL Server中,使用nolock指令。它允许select命令完成而不必等待-通常是其他事务完成。
SELECT * FROM Orders (nolock) where UserName = 'momma'
我喜欢用
isnull(SomeColThatMayBeNull, '')
过度
coalesce(SomeColThatMayBeNull, '')
当我不需要多参数支持时,凝聚会为您提供。
http://blog.falafel.com/2006/04/05/SQLServerArcanaISNULLVsCOALESCE.aspx
不要用“ sp_”作为存储过程名称的前缀,因为系统过程都以“ sp_”开头,并且在调用过程时,SQL Server必须更加努力地寻找过程。