SQL Server 百万数据查询优化技巧三十则

互联网时代的进程越走越深,使用MySQL的人也越来越多,关于MySQL的数据库优化指南很多,而关于SQL SERVER的T-SQL优化指南看上去比较少,近期有学习SQLSERVER的同学问到SQL SERVER数据库有哪些优化建议?本文列举了部分常见的优化建议,具体内容如下:
1、优化建议索引优化:eg:考虑一个订单表 Orders,其中有列 OrderDate 和 CustomerID 。如果经常需要按订单日期范围和顾客ID进行查询,可以在这两列上建立复合索引,以提高查询性能 。
NULL 值判断避免全表扫描:eg:对于包含 status 列的用户表 Users,避免使用 SELECT * FROM Users WHERE status IS NULL,可以在设计表时设置 status 默认值,确保所有用户都有一个状态 , 然后使用 SELECT * FROM Users WHERE status = 0 进行查询 。
!= 或 <> 操作符避免全表扫描:eg:考虑一个产品表 Products,如果要查询所有不属于某个特定类别的产品 , 避免使用 SELECT * FROM Products WHERE CategoryID != 5,而是使用 SELECT * FROM Products WHERE CategoryID <> 5 。
OR 连接条件避免全表扫描:eg:对于一个学生成绩表 Grades , 如果需要查询得分为 A 或 B 的记录,避免使用 SELECT * FROM Grades WHERE Grade = 'A' OR Grade = 'B',而是使用 SELECT * FROM Grades WHERE Grade = 'A' UNION ALL SELECT * FROM Grades WHERE Grade = 'B' 。
IN 和 NOT IN 避免全表扫描:eg:考虑一个员工表 Employees,如果需要查询属于某个特定部门的员工,避免使用 SELECT * FROM Employees WHERE DepartmentID IN (1, 2, 3),而是使用 SELECT * FROM Employees WHERE DepartmentID BETWEEN 1 AND 3 。
LIKE 查询优化:eg:在一个文章表 Articles 中,如果需要模糊查询标题包含关键词的文章,避免使用 SELECT * FROM Articles WHERE Title LIKE '%SQL%',可以考虑全文检索或者其他优化方式 。
参数使用避免全表扫描:【SQL Server 百万数据查询优化技巧三十则】eg:在一个订单表 Orders 中,如果需要根据输入的订单号查询订单信息,避免使用 SELECT * FROM Orders WHERE OrderID = @OrderID , 可以使用强制索引的方式 , 如 SELECT * FROM Orders WITH(INDEX(OrderID_Index)) WHERE OrderID = @OrderID 。
字段表达式操作避免全表扫描:eg:在一个商品表 Products 中 , 如果需要查询价格除以2等于100的商品,避免使用 SELECT * FROM Products WHERE Price/2 = 100,可以改为 SELECT * FROM Products WHERE Price = 100*2 。
字段函数操作避免全表扫描:eg:在一个员工表 Employees 中,如果需要查询名字以"Smith"开头的员工,避免使用 SELECT * FROM Employees WHERE LEFT(LastName, 5) = 'Smith',可以改为 SELECT * FROM Employees WHERE LastName LIKE 'Smith%' 。
不要在“=”左边进行函数、算术运算:eg:在一个库存表 Inventory 中,避免使用 SELECT * FROM Inventory WHERE YEAR(StockDate) = 2023,而是使用 SELECT * FROM Inventory WHERE StockDate >= '2023-01-01' AND StockDate < '2024-01-01' 。
索引字段顺序使用避免全表扫描:eg:在一个订单表 Orders 中,如果有复合索引 (CustomerID, OrderDate),查询时应该先使用 CustomerID , 如 SELECT * FROM Orders WHERE CustomerID = @CustomerID AND OrderDate BETWEEN @StartDate AND @EndDate 。
避免写没有意义的查询:eg:不建议使用 SELECT col1, col2 INTO #t FROM t WHERE 1 = 0,可以改为明确创建表结构并使用 CREATE TABLE #t (...) 。
使用 EXISTS 代替 IN:eg:在一个产品表 Products 中,避免使用 SELECT * FROM Products WHERE ProductID IN (SELECT ProductID FROM DiscontinuedProducts),可以改为 SELECT * FROM Products WHERE EXISTS (SELECT 1 FROM DiscontinuedProducts WHERE ProductID = Products.ProductID) 。
索引不一定对所有查询有效:eg:在一个性别字段 Gender 几乎均匀分布的表中 , 对 Gender 建立索引可能不会提高查询效率 。
索引数量谨慎选择:eg:在一个订单表 Orders 中 , 不宜过多地在每个列上建立索引,需要根据查询和更新的具体需求进行权衡 。
更新 clustered 索引数据列谨慎操作:eg:在一个用户表 Users 中,如果频繁更新用户姓名,考虑是否将姓名列设为非聚集索引,以避免整个表记录顺序调整 。
使用数字型字段:eg:在一个学生成绩表 Grades 中,如果考试成绩以整数形式表示,使用整数型字段而非字符型字段 。
使用 VARCHAR/NVARCHAR:eg:在一个文章表 Articles 中,如果存储文章内容,使用 VARCHAR(MAX) 而非 TEXT 。
避免使用 SELECT *:eg:在一个员工表 Employees 中,避免使用 SELECT * FROM Employees,而是明确指定需要的列,如 SELECT EmployeeID, FirstName, LastName FROM Employees 。


推荐阅读