如何编写最佳SQL查询

时间:2011-05-02 13:34:41

标签: sql

我搜索了stackoverflow,但每个人都要求优化他们已经完成的查询。

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

例如,已知的事实是,编写SELECT * FROM是一件值得避免的事情,因为sql引擎必须进行“不可见”查询才能知道应该显示哪些列。

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

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

9 个答案:

答案 0 :(得分:14)

我的列表是特定于SQL Server的(我确信还有更多):

使用sargable where子句 - 这意味着没有函数特别是标量UDF在where where子句中

当您要查找与第二个表不匹配的行时,没有EXISTS往往比具有where null为null结构的左连接更快的选择。

相关的子查询倾向于逐行运行并且速度非常慢。

调用其他视图的视图无法编入索引并变得非常慢,尤其是如果在大型表中获得多个级别。

当你有一个连接时,特别要避免选择*,因为至少有一个列被发送两次,这会浪费服务器,数据库和网络资源。

通常可以使用速度更快的基于集合的逻辑替换游标 以正确的方式存储数据时,可以避免大量的动态转换。

更新时,请确保添加where子句,以便不更新新值和旧值相同的行。这可能是更新10,000,000行和更新15之间的差异。示例(Tsql Update结构,如果你使用另一个数据库,你可能必须查找正确的语法,但它应该给你这个想法。):

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

检查索引。 SQL Seerver不会自动索引外键。如果它们用于连接,则通常需要对它们编制索引。

如果您经常在字段上使用函数,则可能无法正确存储它(或者您应该有一个持久的计算字段,并且每次选择列时都不会进行一次转换。)

你最好的选择是为你选择的数据库获得一本好的性能调优书(最好的是数据库特定的),并阅读有关编写查询的章节。

答案 1 :(得分:7)

  • Views are macros,而不是魔术
  • EXISTs和NOT EXIST通常效果最佳
  • 列上的功能(请参阅Joel C的回答)
  • 注意implicit conversion(例如,与int参数相比较的smallint列)
  • 了解covering indexes
  • 了解聚合:停止思考循环
  • ...

编辑,2012年2月:

避免使用这些"Ten Common SQL Programming Mistakes"

答案 2 :(得分:5)

在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等

答案 3 :(得分:4)

关于优化查询的一些一般观点:

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

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

答案 4 :(得分:2)

这是关于SQL服务器上的最佳实践和性能的良好链接。 http://www.sql-server-performance.com/articles/dev/sql_best_practices_p1.aspx

答案 5 :(得分:1)

我实际上无法验证您的声明,但可以说不使用*听起来很安静逻辑,我可以做的是为它们添加一两点,如果你可以从tablename中提供一个select列名添加一个where子句它有帮助很多,因为你会减少许多不必要的行和数据行可能被拉起来,也避免交叉连接和欢迎内部连接,外部连接或更完整的连接应该是根据我的个人经验去的方式: )

答案 6 :(得分:0)

在列表中添加一些提示:

使用EXISTS / NOT EXISTS代替IN / 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)  

在可能使用UNION ALL 时避免使用UNION 当你不需要排除重复的行或你确定它不会返回重复的行

在可能使用WHERE

时避免使用HAVING
 --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

当您有一对多表连接时,请使用EXISTS而不是DISTINCT

--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)  

我希望这些提示有所帮助,期待更多提示;)

答案 7 :(得分:0)

编写查询的简单规则:

  1. 从最小的表中写出abc.pdf".split('.')["abc.pdf".split('.').length -1]; 子句。这有助于在我们搜索少量数据时更有效地查找数据。

  2. 首先,您应该写FROM,然后INNER JOIN。这有助于减少SQL Engine将搜索数据的行数。

    例如:

    LEFT OUTER JOIN
  3. 使用别名和架构名称来避免SQL Server进行架构扫描。 As using schema name helps to cashe your query plan for ad-hoc queries that can be reusable by other users, not only for your queries.

  4. 避免使用SELECT pe.Name, de.Name, bu.Name FROM dbo.Persons pe INNER JOIN dbo.Departments de ON pe.ID = de.id_Person -- at first INNER JOIN LEFT JOIN dbo.Bureau bu ON bu.ID = de.id_Bureau -- then LEFT OUTER JOIN

答案 8 :(得分:0)

根据我的阅读,使用BETWEEN而不是使用索引AND来对索引进行两次检查可以提高性能,因为您的数据库在发现索引有效时可能无法充分利用索引的好处在ANDOR的两侧使用。

查询优化器可能无法直觉这是范围检查,并且索引排序可以派上用场。相反,它可以对每种条件进行扫描,然后合并结果。另一方面,使用BETWEEN子句将索引列与两个值进行比较,这一点非常清楚。