在数据库中的表列中应用适当的索引
这将确保每个表都创建了一个聚集索引(因此,表的相应页面在磁盘中根据主键字段进行物理排序)。因此,任何使用主键从表中检索数据的操作,或对主键字段或 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 的性能最慢。
- IN 是有效的,只有当大多数用于选择的过滤条件都放在 SQL 语句的子查询中时。
- 当用于选择的大多数筛选条件位于 SQL 语句的主查询中时,EXISTS 是有效的。
尽量避免动态SQL
除非确实需要,否则尽量避免使用动态 SQL,因为: 动态 SQL 很难调试和排除故障。如果用户向动态 SQL 提供输入,则存在 SQL 注入攻击的可能性。
尽量避免使用临时表
除非确实需要,否则尽量避免使用临时表。而是使用表变量。在 99% 的情况下,表变量驻留在内存中,因此速度要快得多。临时表驻留在 TempDb 数据库中。因此对临时表进行操作需要数据库间通信,因此会更慢。
代替 LIKE 搜索,使用全文搜索来搜索文本数据
全文搜索总是优于 LIKE 搜索。全文搜索将使您能够实现使用 LIKE 搜索无法实现的复杂搜索条件,例如搜索单个单词或短语(以及可选地对结果集进行排名)、搜索靠近另一个单词或短语词或短语,或搜索特定词的同义形式。实现全文搜索比 LIKE 搜索更容易实现(尤其是在搜索需求复杂的情况下)。
尝试使用 UNION 来实现“或”操作
尽量不要在查询中使用“OR”。而是使用“UNION”来组合两个有区别的查询的结果集。这将提高查询性能。如果不需要区分结果,最好使用 UNION ALL。UNION ALL 比 UNION 更快,因为它不必对结果集进行排序以找出可区分的值。
为大对象实现延迟加载策略
将大对象列(如 VARCHAR(MAX)、图像、文本等)存储在与主表不同的表中,并在主表中放置对大对象的引用。检索一次查询中的所有主表数据,如果需要加载大对象,则仅在需要时才从大对象表中检索大对象数据。
在用户定义的函数中实施以下良好实践
不要在存储过程、触发器、函数和批处理中重复调用函数。例如,您可能在过程的许多地方都需要字符串变量的长度,但不要在需要时调用 LEN 函数;相反,调用 LEN 函数一次,并将结果存储在变量中以备后用。
在触发器中实施以下良好实践
- 尽量避免使用触发器。触发触发器并执行触发事件是一个昂贵的过程。
- 永远不要使用可以使用约束来实现的触发器。
- 不要对不同的触发事件(插入、更新和删除)使用相同的触发器。
- 不要在触发器中使用事务代码。触发器始终在触发触发器的代码的事务范围内运行。