吧务
level 11
tmtony
楼主
三个实用的 SQL Server 使用技巧,涵盖开发效率和性能优化:
1. 使用 `ROW_NUMBER()` 实现高效分页或去重
场景:避免使用低效的 `NOT IN` 或临时表分页,或对重复数据取最新记录。
-- 分页查询(获取第11-20条记录)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (ORDER BY CreateDate DESC) AS RowNum
FROM Orders
) AS Sub
WHERE RowNum BETWEEN 11 AND 20;
-- 去重(保留每个客户最新订单)
WITH RankedOrders AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS Rank
FROM Orders
)
SELECT *
FROM RankedOrders
WHERE Rank = 1;
优势:窗口函数在服务器内高效排序,减少I/O开销。
2. 利用 `WITH (NOLOCK)` 处理高并发读场景(谨慎使用)
场景:允许脏读(读取未提交数据),提升查询速度,适用于允许短暂数据不一致的报表系统。
SELECT ProductName, Quantity
FROM Inventory WITH (NOLOCK) -- 不加表锁
WHERE CategoryID = 5;
注意:
- 可能读到正在回滚的数据(脏读)。
- 适用场景:实时性要求高、数据准确性非严格的统计。
- 替代方案:使用快照隔离级别(`SET TRANSACTION ISOLATION LEVEL SNAPSHOT`)。
3. 使用 `EXISTS()` 替代 `IN` 提升子查询性能
场景:检查是否存在关联记录时,`EXISTS` 在找到第一条匹配后即停止扫描,效率更高。
-- 查找有订单的客户
SELECT CustomerID, Name
FROM Customers c
WHERE EXISTS (
SELECT 1
FROM Orders o
WHERE o.CustomerID = c.CustomerID
);
-- 比 IN 更高效:
-- SELECT ... WHERE CustomerID IN (SELECT CustomerID FROM Orders)
原理:`EXISTS` 是短路操作,`IN` 需处理整个子查询结果集。
⚠️ 附加高级技巧:索引提示(强制索引)
场景:当查询优化器选错索引时,手动指定最优索引。
SELECT *
FROM Sales.Orders WITH (INDEX(IX_OrderDate)) -- 强制使用索引
WHERE OrderDate > '2023-01-01';
慎用:仅在明确优化器行为错误时使用,否则可能适得其反。
根据实际场景灵活组合这些技巧,能显著提升查询效率和开发体验!
2025年05月30日 15点05分
1
1. 使用 `ROW_NUMBER()` 实现高效分页或去重
场景:避免使用低效的 `NOT IN` 或临时表分页,或对重复数据取最新记录。
-- 分页查询(获取第11-20条记录)
SELECT *
FROM (
SELECT *,
ROW_NUMBER() OVER (ORDER BY CreateDate DESC) AS RowNum
FROM Orders
) AS Sub
WHERE RowNum BETWEEN 11 AND 20;
-- 去重(保留每个客户最新订单)
WITH RankedOrders AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS Rank
FROM Orders
)
SELECT *
FROM RankedOrders
WHERE Rank = 1;
优势:窗口函数在服务器内高效排序,减少I/O开销。
2. 利用 `WITH (NOLOCK)` 处理高并发读场景(谨慎使用)
场景:允许脏读(读取未提交数据),提升查询速度,适用于允许短暂数据不一致的报表系统。
SELECT ProductName, Quantity
FROM Inventory WITH (NOLOCK) -- 不加表锁
WHERE CategoryID = 5;
注意:
- 可能读到正在回滚的数据(脏读)。
- 适用场景:实时性要求高、数据准确性非严格的统计。
- 替代方案:使用快照隔离级别(`SET TRANSACTION ISOLATION LEVEL SNAPSHOT`)。
3. 使用 `EXISTS()` 替代 `IN` 提升子查询性能
场景:检查是否存在关联记录时,`EXISTS` 在找到第一条匹配后即停止扫描,效率更高。
-- 查找有订单的客户
SELECT CustomerID, Name
FROM Customers c
WHERE EXISTS (
SELECT 1
FROM Orders o
WHERE o.CustomerID = c.CustomerID
);
-- 比 IN 更高效:
-- SELECT ... WHERE CustomerID IN (SELECT CustomerID FROM Orders)
原理:`EXISTS` 是短路操作,`IN` 需处理整个子查询结果集。
⚠️ 附加高级技巧:索引提示(强制索引)
场景:当查询优化器选错索引时,手动指定最优索引。
SELECT *
FROM Sales.Orders WITH (INDEX(IX_OrderDate)) -- 强制使用索引
WHERE OrderDate > '2023-01-01';
慎用:仅在明确优化器行为错误时使用,否则可能适得其反。
根据实际场景灵活组合这些技巧,能显著提升查询效率和开发体验!