2011-05-02 116 views
14

我已经搜索了四周的stackoverflow,但每个人都要求优化他们已经完成的查询。如何编写最佳SQL查询

我想知道,做什么的基本内容,创建查询时要避免什么。

例如,这是一个已知的事实,写作SELECT * FROM是一件要避免的事情,因为sql引擎必须做一个“隐形”查询来知道应该显示哪些列。

也知道between @min_number AND @max_numberId >= @min_number AND Id <= @max_number更好,但我不记得原因。这可能是因为之间是由引擎控制在较低级别的句子,并创建迭代来显示regs以某种方式“处理”。但我不确定。

有人可以验证这些,并列出最常见的该做什么,该怎么避免

+0

我会与'select * from'的情况争论。取决于特定的SQL编译器(每个数据库引擎如何编译它接收的某种字节码的SQL)的工作方式,它可能需要或可能不需要额外的工作。你没有指定任何特定的数据库。 – 2011-05-02 13:38:27

+1

'between'是否比'<' and '>'更好取决于特定的SQL优化器。有了它,它总能看到它是一个范围,但它可能会或可能不会被使用,而'<' and '>'它可能会错过它的范围。 – 2011-05-02 13:40:12

+1

优秀的问题 – HLGEM 2011-05-02 14:00:08

回答

11

我的目录是SQL Server特定(我敢肯定,很多更多):

使用优化搜索where子句 - 这意味着没有特别的功能标UDF在where子句中

WHERE NOT EXISTS往往是比左连接更快的选择,其中id是null结构,当您查找与第二个表不匹配的行时。

相关的子查询往往逐行运行,速度非常慢。

调用其他视图的视图不能被编入索引,并且变得非常慢,特别是如果您在大型表上获得多个级别。

由于至少有一列发送两次,这是浪费服务器和数据库及网络资源,所以选择*时应特别避免。

光标通常可以用速度更快的基于集合的逻辑来代替 当您以正确的方式存储数据时,可以避免很多即时转换。

更新时,请确保添加了where子句,以便不更新新值和旧值相同的行。这可能是更新10,000,000行和更新15样品之间的differnce(TSQL更新结构,如果使用其他数据库,你可能要查找正确的语法,但它应该给你的想法。):

Update t 
set field1 = t2.field2 
from table1 t 
join table2 t2 on t.tid = t2.tid 
Where t.field1 <> t2.field2 

或者

Update t 
set field1 = @variable 
from table1 t 
Where t.field1 <> @variable 

如果你经常使用的一个字段的功能,你可能无法正确保存它(或你应该有一个持久计算领域,并做改造每次选择列的时间只有一次没有。)

你最好b et是为你的数据库选择一个好的性能调优书(最适合数据库的最好的),并阅读有关编写查询的章节。

+0

Thanks @HLGEM是SQL Server的特定原因,因为这不会发生在其他引擎上,或者因为您在SQL Server上工作,因此只能说出您的知识在那个编译器中? – apacay 2011-05-02 14:39:15

+0

性能调整是数据库特定的。我怀疑其中的一些在其他数据库引擎上也是一样的,但不知道,因为我只用SQl Server深入工作。这就是为什么阅读关于您所使用的特定dbs的性能调优非常重要的原因。而且这也是为什么很多没有绑定到一个数据库的COTS程序在性能上非常糟糕的原因。 – HLGEM 2011-05-02 14:50:55

+0

我和你一样。我几乎完全与MS SQL Srv一起工作。社区wiki可以写在这里吗?我会编译你所有人都说过的话。 – apacay 2011-05-03 18:43:48

4

在您的WHERE子句中,避免使用列作为函数的输入,因为这会导致全表扫描而不能使用索引。某些平台上的查询优化器比其他平台做得更好,但通常更安全。举例来说,如果你从过去的30天寻找记录,做对你是比较反对,并不反对你的列中的日期数据操作:

BAD

WHERE DATEADD(DAY, 30, [RecordDate]) > GETDATE() 

这可能导致全表扫描(取决于您的平台的查询优化器),即使[RecordDate]已编入索引,因为必须对DATEADD(DAY, 30, [RecordDate])进行评估,以便将其与GETDATE()进行比较。如果您将其更改为:

更好

WHERE [RecordDate] > DATEADD(DAY, -30, GETDATE()) 

这将现在总是能够在[RecordDate]使用索引不管查询计划优化器是多么好你的平台上,因为DATEADD(DAY, -30, GETDATE())被计算一次然后可以用作索引中的查找。同样的原则也适用于使用CASE声明,UDF的,等

+0

始终是好的 – gbn 2011-05-02 14:25:59

+0

同样适用于select语句 – Magnus 2011-05-02 14:27:29

6
  • Views are macros,不是魔术
  • 存在和不存在的列上工作最通常
  • 功能(见乔尔C'S答案)
  • 谨防implicit conversion(如SMALLINT柱相比,INT参数)
  • 了解covering indexes
  • Denormalise 之后你看问题
  • 了解聚合:停止循环思考
  • ...

编辑,2012年2月:

避免这些"Ten Common SQL Programming Mistakes"

+2

+1“停止思考循环”。对于大多数数据库新手来说,基于集合的思维是最难的事情。 – 2011-05-02 15:15:32

1

我不能实际验证您的要求,但可以说,不使用*太安静逻辑,有什么我可以做的就是添加一个或两个点他们,如果你可以一起从表名中选择一个列名添加一个where子句,它会有很大的帮助,因为你可以减少很多不必要的行和可能被拉起的数据行,也可以避免交叉连接和欢迎内部根据我的个人经验,连接,外连接或更充分的连接应该是顺其自然的方式:)

0

添加一些提示,以列表:

使用EXISTS使用UNION时,其可以使用UNION ALL到位的/ NOT EXISTS/NOT IN的索引列

--instead of 
SELECT * FROM table1 
    WHERE id1 NOT IN (SELECT id2 FROM table2) 

--you better write 
SELECT * FROM table1 WHERE NOT EXISTS (SELECT 1 FROM table2 WHERE id1=id2) 

避免
当你不需要排除重复的行或者你确定它不会返回重复的行

避免使用HAVING当我TS可以使用WHERE

--instead of 
SELECT col1, sum(col2) 
    FROM table1 
    GROUP BY col1 
HAVING col1 > 0 

--you better write : 
SELECT col1, sum(col2) 
    FROM table1 
    WHERE col1 > 0 
GROUP BY col1 

使用,当你有一个对多表连接

--instead of 
SELECT distinct a.col1, a.col2 
    FROM table1 a, table2 b 
WHERE a.id = b.id 

--you better write 
SELECT a.col1, a.col2 
    FROM table1 a 
WHERE EXISTS (SELECT 1 FROM table2 b where a.id = b.id) 

我希望这几个小技巧帮助,期待更多的提示exists代替DISTINCT;)

+0

我认为现在大多数数据库现在都为IN和EXISTS创建相同的查询计划 – Magnus 2011-05-02 14:57:23

+1

@Magnus:正确,但不是IN和NOT EXISTS是非常不同的。 @mcha:你在最后一个例子中使用了ANSI-89隐式连接......应该是ANSI-92 EXPLICIT join ;-) – gbn 2011-05-02 15:21:16

+0

@gbn在SQL Server 2008上执行了一些针对NOT EXISTS和NOT IN的查询测试,他们都制定了相同的计划。 – Magnus 2011-05-02 15:32:31

4

有关优化查询的几个基本点:

  • 了解你的数据。了解你的数据。 了解你的信息。我冒昧猜测,所有数据库性能问题中有一半来自对数据和查询要求的不完全理解。知道你的查询通常会返回50行还是500万行。知道你是否需要找回3列或50列。知道哪些列是表格上的关键列,并对这些列进行过滤。

  • 了解您的数据库结构。如果您使用的是第三种常规形式的数据库,请认识到此结构通常适用于查询在各行上操作的大量小型事务性语句。如果您在星形或雪花设计中工作,请认识到它已针对大型查询和聚合进行了优化。

+1

@N这是最有用的! ty为你的贡献。然而,这个问题指向了句法优化。我毫不怀疑这就是某个语义学习者所知道的。但这不是我正在寻找的答案。 – apacay 2011-05-03 18:38:42