This section contains the code and execution plans for Chapter 6, “Sorting and Grouping” in a SQL Server database.
Indexed Order By
DROP INDEX sales_date ON sales;
GO
CREATE INDEX sales_dt_pr ON sales (sale_date, product_id);
GO
EXEC sp_updatestats;
GO
SET STATISTICS PROFILE ON;
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date = DATEADD(day, -1, GETDATE())
ORDER BY sale_date, product_id;The execution does not perform a sort operation:
Nested Loops(Inner Join, OUTER REFERENCES:[Bmk1000])
|--Index Seek(OBJECT:([sales].[sales_dt_pr]),
| SEEK:[sales].[sale_date]=dateadd(day,(-1),getdate())
| ORDERED FORWARD)
|--RID Lookup(OBJECT:([sales]),
SEEK:[Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARDSQL Server uses the same execution plan, when sorting by PRODUCT_ID only.
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date = DATEADD(day, -1, GETDATE())
ORDER BY product_id;Using an greater or equals condition requires an Sort operation:
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
ORDER BY product_id;Although the row estimate got lower, causing the cost also to be lower:
Sort(ORDER BY:([test].[dbo].[sales].[product_id] ASC))
|--Nested Loops(Inner Join, OPTIMIZED WITH UNORDERED PREFETCH)
|--Compute Scalar(DEFINE:([Expr1009]=BmkToPage([Bmk1000])))
| |--Nested Loops(Inner Join)
| |--Compute Scalar([...])
| | |--Constant Scan
| |--Index Seek(OBJECT:([sales].[sales_dt_pr]),
| SEEK:([sales].[sale_date] > [Expr1007]
| AND [sales].[sale_date] < NULL) ORDERED FORWARD)
|--RID Lookup(OBJECT:([sales]),
SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD)Indexing ASC, DESC and NULLS FIRST/LAST
Scanning an index backwards:
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
ORDER BY sale_date DESC, product_id DESC;Mixing ASC and DESC causes an explicit sort:
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
ORDER BY sale_date ASC, product_id DESC;Ordering the index with mixed ASC/DESC modifiers:
DROP INDEX sales_dt_pr ON sales;
GO
CREATE INDEX sales_dt_pr
ON sales (sale_date ASC, product_id DESC);
GO
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
ORDER BY sale_date ASC, product_id DESC;SQL Server 2008R2 does not implement the order by NULLS extension.
SELECT sale_date, product_id, quantity
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
ORDER BY sale_date ASC, product_id DESC NULLS LAST;Indexed Group By
Pipelined group by execution:
SELECT product_id, SUM(eur_value)
FROM sales
WHERE sale_date = DATEADD(day, -1, GETDATE())
GROUP BY product_id;Explicit Sort/Group when retrieving the stats for two days (parallelism disable for plan readability):
SELECT product_id, SUM(eur_value)
FROM sales
WHERE sale_date >= DATEADD(day, -1, GETDATE())
GROUP BY product_id
OPTION (MAXDOP 1);The Hash-Algorithm is used when aggregating a larger set:
SELECT product_id, SUM(eur_value)
FROM sales
WHERE sale_date >= DATEADD(day, -100, GETDATE())
GROUP BY product_id
OPTION (MAXDOP 1);
