-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path37_10_Indexing_Mistakes.sql
More file actions
349 lines (282 loc) · 10.1 KB
/
37_10_Indexing_Mistakes.sql
File metadata and controls
349 lines (282 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/**************************************************************
* SQL Server 2022: Indexing Bad Practices and Optimal Approaches
* Description: This script demonstrates 10 common indexing bad
* practices and provides the correct (optimal) approach
* for each scenario. Adjust table/index names and designs
* as needed based on your workload and query patterns.
**************************************************************/
-------------------------------------------------
-- Region: 1. Over-indexing vs. Optimal Composite Indexes
-------------------------------------------------
/*
BAD PRACTICE:
- Creating separate indexes on individual columns, causing high maintenance overhead.
CORRECT APPROACH:
- Analyze query patterns and create a composite (covering) index that supports common filtering
and sorting requirements.
*/
-- Setup sample table dbo.Orders
IF OBJECT_ID('dbo.Orders', 'U') IS NOT NULL
DROP TABLE dbo.Orders;
GO
CREATE TABLE dbo.Orders (
OrderID INT IDENTITY PRIMARY KEY,
CustomerID INT,
OrderDate DATETIME,
Status VARCHAR(50),
Amount DECIMAL(10,2)
);
GO
-- BAD PRACTICE: Separate indexes on individual columns
CREATE NONCLUSTERED INDEX idx_Orders_CustomerID ON dbo.Orders(CustomerID);
CREATE NONCLUSTERED INDEX idx_Orders_OrderDate ON dbo.Orders(OrderDate);
CREATE NONCLUSTERED INDEX idx_Orders_Status ON dbo.Orders(Status);
CREATE NONCLUSTERED INDEX idx_Orders_Amount ON dbo.Orders(Amount);
GO
-- CORRECT APPROACH: Remove individual indexes and create one composite covering index
DROP INDEX idx_Orders_CustomerID ON dbo.Orders;
DROP INDEX idx_Orders_OrderDate ON dbo.Orders;
DROP INDEX idx_Orders_Status ON dbo.Orders;
DROP INDEX idx_Orders_Amount ON dbo.Orders;
GO
CREATE NONCLUSTERED INDEX idx_Orders_Composite
ON dbo.Orders(CustomerID, OrderDate)
INCLUDE (Status, Amount);
GO
-------------------------------------------------
-- Region: 2. Indexing Frequently Updated Columns
-------------------------------------------------
/*
BAD PRACTICE:
- Indexing columns that are updated frequently, increasing maintenance cost.
CORRECT APPROACH:
- Avoid indexing volatile columns unless they are critical for query performance.
*/
-- Setup sample table dbo.Employees
IF OBJECT_ID('dbo.Employees', 'U') IS NOT NULL
DROP TABLE dbo.Employees;
GO
CREATE TABLE dbo.Employees (
EmployeeID INT IDENTITY PRIMARY KEY,
Name VARCHAR(100),
LastLoginDate DATETIME
);
GO
-- BAD PRACTICE: Creating an index on a frequently updated column
CREATE NONCLUSTERED INDEX idx_Employees_LastLoginDate_Bad ON dbo.Employees(LastLoginDate);
GO
-- CORRECT APPROACH: Drop the index unless testing shows a performance benefit
DROP INDEX idx_Employees_LastLoginDate_Bad ON dbo.Employees;
GO
-- (Optionally, create the index only if needed)
-- CREATE NONCLUSTERED INDEX idx_Employees_LastLoginDate_Good ON dbo.Employees(LastLoginDate);
GO
-------------------------------------------------
-- Region: 3. Creating Covering Indexes with INCLUDE Clause
-------------------------------------------------
/*
BAD PRACTICE:
- Creating an index that doesn't cover the query, causing extra lookups.
CORRECT APPROACH:
- Use the INCLUDE clause to create a covering index that satisfies the query entirely.
*/
-- Setup sample table dbo.Products
IF OBJECT_ID('dbo.Products', 'U') IS NOT NULL
DROP TABLE dbo.Products;
GO
CREATE TABLE dbo.Products (
ProductID INT IDENTITY PRIMARY KEY,
ProductName VARCHAR(200),
CategoryID INT,
Price DECIMAL(10,2),
Stock INT
);
GO
-- BAD PRACTICE: Index without covering additional columns
CREATE NONCLUSTERED INDEX idx_Products_CategoryID_Bad ON dbo.Products(CategoryID);
GO
-- CORRECT APPROACH: Drop the index and create one that includes needed columns
DROP INDEX idx_Products_CategoryID_Bad ON dbo.Products;
GO
CREATE NONCLUSTERED INDEX idx_Products_CategoryID_Good
ON dbo.Products(CategoryID)
INCLUDE (ProductName, Price);
GO
-------------------------------------------------
-- Region: 4. Ordering Columns in Composite Indexes
-------------------------------------------------
/*
BAD PRACTICE:
- Incorrect ordering of columns in a composite index.
CORRECT APPROACH:
- Place columns with equality predicates before those with range predicates.
*/
-- Setup sample table dbo.Sales
IF OBJECT_ID('dbo.Sales', 'U') IS NOT NULL
DROP TABLE dbo.Sales;
GO
CREATE TABLE dbo.Sales (
SaleID INT IDENTITY PRIMARY KEY,
RegionID INT,
SaleDate DATETIME,
Total DECIMAL(10,2)
);
GO
-- BAD PRACTICE: Incorrect order – range column (SaleDate) first, then equality column (RegionID)
CREATE NONCLUSTERED INDEX idx_Sales_Bad ON dbo.Sales(SaleDate, RegionID);
GO
-- CORRECT APPROACH: Equality column first, then range column
DROP INDEX idx_Sales_Bad ON dbo.Sales;
GO
CREATE NONCLUSTERED INDEX idx_Sales_Good ON dbo.Sales(RegionID, SaleDate);
GO
-------------------------------------------------
-- Region: 5. Using Filtered Indexes Appropriately
-------------------------------------------------
/*
BAD PRACTICE:
- Creating an index on the entire table when only a subset is frequently queried.
CORRECT APPROACH:
- Use a filtered index to index only the subset of rows, reducing index size and improving performance.
*/
-- Setup sample table dbo.Logs
IF OBJECT_ID('dbo.Logs', 'U') IS NOT NULL
DROP TABLE dbo.Logs;
GO
CREATE TABLE dbo.Logs (
LogID INT IDENTITY PRIMARY KEY,
EventDate DATETIME,
EventType VARCHAR(50),
Message NVARCHAR(MAX)
);
GO
-- BAD PRACTICE: Full-table index on EventType
CREATE NONCLUSTERED INDEX idx_Logs_EventType_Bad ON dbo.Logs(EventType);
GO
-- CORRECT APPROACH: Use a filtered index for a subset (e.g., 'Error' events)
DROP INDEX idx_Logs_EventType_Bad ON dbo.Logs;
GO
CREATE NONCLUSTERED INDEX idx_Logs_ErrorEventType
ON dbo.Logs(EventType)
WHERE EventType = 'Error';
GO
-------------------------------------------------
-- Region: 6. Indexing Computed Columns Properly
-------------------------------------------------
/*
BAD PRACTICE:
- Indexing a non-persisted computed column, leading to performance overhead.
CORRECT APPROACH:
- Persist the computed column so that it is physically stored, then create the index.
*/
-- Setup sample table dbo.Invoices
IF OBJECT_ID('dbo.Invoices', 'U') IS NOT NULL
DROP TABLE dbo.Invoices;
GO
CREATE TABLE dbo.Invoices (
InvoiceID INT IDENTITY PRIMARY KEY,
Subtotal DECIMAL(10,2),
Tax DECIMAL(10,2)
);
GO
-- BAD PRACTICE: Add non-persisted computed column and index it directly
ALTER TABLE dbo.Invoices ADD Total AS (Subtotal + Tax);
GO
CREATE NONCLUSTERED INDEX idx_Invoices_Total_Bad ON dbo.Invoices((Subtotal + Tax));
GO
-- CORRECT APPROACH: Drop computed column, re-add as PERSISTED, then index it
ALTER TABLE dbo.Invoices DROP COLUMN Total;
GO
ALTER TABLE dbo.Invoices ADD Total AS (Subtotal + Tax) PERSISTED;
GO
CREATE NONCLUSTERED INDEX idx_Invoices_Total_Good ON dbo.Invoices(Total);
GO
-------------------------------------------------
-- Region: 7. Keeping Statistics Up-to-Date
-------------------------------------------------
/*
BAD PRACTICE:
- Not updating statistics after significant data changes.
CORRECT APPROACH:
- Update statistics manually or ensure AUTO_UPDATE_STATISTICS is enabled.
*/
-- Update statistics manually on dbo.Orders table
UPDATE STATISTICS dbo.Orders WITH FULLSCAN;
GO
-- Ensure AUTO_UPDATE_STATISTICS is enabled
ALTER DATABASE CURRENT SET AUTO_UPDATE_STATISTICS ON;
GO
-------------------------------------------------
-- Region: 8. Enforcing Uniqueness with Unique Indexes/Constraints
-------------------------------------------------
/*
BAD PRACTICE:
- Creating a non-unique index on a column expected to contain unique values.
CORRECT APPROACH:
- Use a UNIQUE constraint or index to enforce data integrity.
*/
-- Setup sample table dbo.Users
IF OBJECT_ID('dbo.Users', 'U') IS NOT NULL
DROP TABLE dbo.Users;
GO
CREATE TABLE dbo.Users (
UserID INT IDENTITY PRIMARY KEY,
Username VARCHAR(100) NOT NULL
);
GO
-- BAD PRACTICE: Non-unique index on Username
CREATE NONCLUSTERED INDEX idx_Users_Username_Bad ON dbo.Users(Username);
GO
-- CORRECT APPROACH: Drop the index and enforce uniqueness via a constraint
DROP INDEX idx_Users_Username_Bad ON dbo.Users;
GO
ALTER TABLE dbo.Users
ADD CONSTRAINT UQ_Users_Username UNIQUE (Username);
GO
-------------------------------------------------
-- Region: 9. Regular Maintenance for Index Fragmentation
-------------------------------------------------
/*
BAD PRACTICE:
- Ignoring index fragmentation, which degrades query performance.
CORRECT APPROACH:
- Regularly monitor and maintain indexes using REBUILD or REORGANIZE commands.
*/
-- Rebuild all indexes on the dbo.Orders table to reduce fragmentation
ALTER INDEX ALL ON dbo.Orders REBUILD;
GO
-- Alternatively, reorganize indexes on the dbo.Products table for moderate fragmentation
ALTER INDEX ALL ON dbo.Products REORGANIZE;
GO
-------------------------------------------------
-- Region: 10. Avoiding Indexes on Low-Selectivity Columns
-------------------------------------------------
/*
BAD PRACTICE:
- Creating an index on a column with low cardinality (e.g., Status flag) that provides little filtering benefit.
CORRECT APPROACH:
- Avoid single-column indexes on low-selectivity columns.
- Instead, create composite indexes that include additional columns.
*/
-- Setup sample table dbo.Tickets
IF OBJECT_ID('dbo.Tickets', 'U') IS NOT NULL
DROP TABLE dbo.Tickets;
GO
CREATE TABLE dbo.Tickets (
TicketID INT IDENTITY PRIMARY KEY,
Status VARCHAR(20), -- e.g., 'Open', 'Closed'
CreatedDate DATETIME
);
GO
-- BAD PRACTICE: Single-column index on a low-selectivity column
CREATE NONCLUSTERED INDEX idx_Tickets_Status_Bad ON dbo.Tickets(Status);
GO
-- CORRECT APPROACH: Drop the index and create a composite index
DROP INDEX idx_Tickets_Status_Bad ON dbo.Tickets;
GO
CREATE NONCLUSTERED INDEX idx_Tickets_Status_CreatedDate_Good
ON dbo.Tickets(Status, CreatedDate);
GO
-------------------------------------------------
-- End of Script
-------------------------------------------------