在数据库表列中应用适当的索引
这将确保每个表都创建了一个聚集索引(因此,表的相应页面在磁盘上根据主键字段物理排序)。因此,使用主键从表中检索任何数据,或者使用主键字段进行任何排序操作,或者在where子句中指定任何一系列主键值将非常快地检索表中的数据。
不要在SQL查询中使用“SELECT *”
多余的列可能会被获取,这会增加数据检索时间的开销。
数据库引擎无法利用“覆盖索引”的好处,因此查询执行缓慢。
例如:
SELECT Cash, Age, Amount FROM Investments;
改为:
SELECT * FROM Investments;
尽量避免在Select语句中使用HAVING子句
HAVING子句用于在选择所有行后过滤行,并像过滤器一样使用。请不要将HAVING子句用于任何其他目的。
例如:
SELECT Name, count (Name) FROM Investments WHERE Name!= ‘Test’ AND Name!= ‘Value’ GROUP BY Name;
改为:
SELECT Name, count (Name) FROM Investments GROUP BY Name HAVING Name!= ‘Test’ AND Name!= ‘Value’ ;
尽量减少查询中的子查询块数
有时我们的主查询中可能会有多个子查询。我们应该尽量减少查询中的子查询块数。
例如:
SELECT Amount FROM Investments WHERE (Cash, Fixed) = (SELECT MAX (Cash), MAX (Fixed) FROM Retirements) AND Goal = 1;
替换为:
SELECT Amount FROM Investments WHERE Cash = (SELECT MAX (Cash) FROM Retirements) AND Fixed = (SELECT MAX (Fixed) FROM Retirements) AND Goal = 1;
避免在SELECT列表中选择不必要的列和在连接条件中包含不必要的表
在Select查询中选择不必要的列会增加实际查询的开销,特别是如果不必要的列是LOB类型。
在连接条件中包含不必要的表会强制数据库引擎检索和获取不必要的数据,并增加查询执行时间。
不要在子查询中使用COUNT()聚合函数进行存在性检查
当您使用COUNT()时,SQL Server不知道您正在进行存在性检查。它会计算所有匹配的值,无论是通过表扫描还是通过扫描最小的非聚集索引来进行。
当您使用EXISTS时,SQL Server知道您正在进行存在性检查。当它找到第一个匹配的值时,它返回TRUE并停止查找。
尽量避免在两种类型的列之间进行连接
当在两个不同数据类型的列之间进行连接时,其中一列必须转换为另一列的类型。被转换的列是类型较低的那个。
如果您正在连接具有不兼容类型的表,则其中一个可以使用索引,但查询优化器无法选择要转换的列上的索引。
尽量不要使用COUNT(*)来获取表中的记录数
通常我们使用以下Select语句来获取表格的总行数:
SELECT COUNT(*) FROM [dbo].[PercentageForGoal]
这个查询将执行全表扫描以获取行数。以下查询不需要进行全表扫描。(请注意,这可能并不总是给出100%完美的结果,但仅在您不需要完美计数时很有用。)
SELECT rows FROM sysindexes
WHERE id = OBJECT_ID('[dbo].[PercentageForGoal]') AND indid< 2
尝试在查询中适当使用像EXISTS、IN和JOINS这样的运算符
- 通常情况下,IN的性能最慢。
- 只有在大多数选择的筛选条件放置在SQL语句的子查询中时,IN才是高效的。
- 当大多数选择的筛选条件在SQL语句的主查询中时,EXISTS是高效的。
尽量避免使用动态SQL
除非真正需要,否则尽量避免使用动态SQL,因为:
动态SQL难以调试和排错。
如果用户提供动态SQL的输入,则有可能发生SQL注入攻击。
尽量避免使用临时表
除非真正需要,否则尽量避免使用临时表。而是使用表变量。
在99%的情况下,表变量驻留在内存中,因此速度更快。临时表驻留在TempDb数据库中。因此,在临时表上操作需要进行跨数据库通信,因此速度会更慢。
搜索文本数据时,使用全文本搜索而不是LIKE搜索
全文搜索始终优于LIKE搜索。全文搜索可以实现复杂的搜索条件,这些条件无法使用LIKE搜索实现,例如搜索单个词或短语(并可选地对结果集进行排名),搜索接近另一个词或短语的词或短语,或搜索特定单词的同义形式。实施全文搜索比LIKE搜索更容易(特别是在需要复杂搜索要求的情况下)。
尝试使用UNION来实现“OR”操作
不要在查询中使用“OR”,而是使用“UNION”将两个不同查询的结果集合并。这将提高查询性能。如果不需要区分结果,请使用“UNION ALL”。相对于“UNION”,“UNION ALL”更快,因为它不必对结果集进行排序以查找区分值。
为大型对象实施延迟加载策略
将大型对象列(如VARCHAR(MAX)、Image、Text等)存储在与主表不同的表中,并在主表中放置对大型对象的引用。检索查询中的所有主表数据,如果需要加载大型对象,则仅在需要时从大型对象表中检索大型对象数据。
在用户定义函数中实现以下良好实践
不要在存储过程、触发器、函数和批处理中重复调用函数。例如,您可能需要在过程的许多地方使用字符串变量的长度,但不要每次需要时都调用LEN函数;相反,调用LEN函数一次,并将结果存储在变量中以供以后使用。
在触发器中实现以下良好实践
- 尽量避免使用触发器。触发触发器并执行触发事件是一个昂贵的过程。
- 永远不要使用可以使用约束实现的触发器。
- 不要为不同的触发事件(插入、更新和删除)使用相同的触发器。
- 不要在触发器内使用事务性代码。触发器始终在触发触发器的代码的事务范围内运行。