- Try to use the
WHEREclause in yourSELECTstatements whenever possible. - Avoid using Cursors as much as possible.
Try to rewrite Cursor logic using set-based approaches.
One reason to avoid Cursors is that eachFETCHoperation is equivalent to a separateSELECT, which can be very costly. - Make sure your
SELECTstatement really needsDISTINCT. Avoid using it unnecessarily. - In your
SELECTstatements, only specify the columns you actually need.
Avoid usingSELECT *as much as possible, since it can prevent index usage and reduce performance. - The
SET ROWCOUNTcommand performs a similar task to theTOPclause, butTOPis generally more efficient. - Prefer using
EXISTSandINinstead ofNOT EXISTSandNOT INwhen possible, as they often provide better performance. - Use Constraints when necessary, such as
PRIMARY KEY,FOREIGN KEY, andDEFAULT. - Avoid using multiple mechanisms to enforce the same rule.
For example, if referential integrity is enforced usingPRIMARY KEYandFOREIGN KEY, do not duplicate this logic in Triggers, as it adds unnecessary overhead. - When you can choose between
JOINandSubQuery, preferJOINbecause it is usually faster. - If both
INandEXISTScan be used, preferEXISTSas it is generally more efficient. - Avoid using functions like
SUBSTRINGin theWHEREclause.
They can cause table scans instead of index seeks.
(This also applies to functions likeRIGHT, etc.) - Avoid using transformation functions in the
WHEREclause whenever possible. - Avoid using
DISTINCTandORDER BYunless they are truly necessary. - If your application frequently performs wildcard searches on
CHARorVARCHAR(e.g.,LIKE '%value%'), consider using Full-Text Search. - You can use
GROUP BYwith or without aggregation functions, but avoid using it unnecessarily without aggregation. - Prefer Derived Tables over Temporary Tables when possible.
- Avoid non-SARGable expressions in the
WHEREclause (e.g., applying functions on columns).
Rewrite conditions so indexes can be used effectively. - Create indexes on columns frequently used in
WHERE,ORDER BY,GROUP BY,TOP, andDISTINCT. - As a rule of thumb, every table should have at least one Clustered Index.
Typically, columns with sequential values (likeIDENTITY) are good candidates. - Be careful not to create duplicate indexes unintentionally.
- Avoid creating indexes in the following cases:
- When the optimizer does not use them
- On very small tables
- On very wide columns
- On
TEXT,NTEXT, orIMAGEcolumns - When the table is rarely used
- Sometimes splitting a composite index into multiple single-column indexes can improve performance (test to confirm).
- If tables are frequently joined, create indexes on the join columns.
- Prefer creating
UNIQUEindexes when possible, as they improve search performance. - Avoid using
FLOATorREALcolumns asPRIMARY KEY. - Do not create multiple Clustered Indexes on the same table.
- Avoid creating Clustered Indexes on columns that are frequently updated.
- Choose columns with high query usage for Clustered Indexes.
- A
PRIMARY KEYdoes not always have to be a Clustered Index. - Avoid using Clustered Indexes on
GUIDcolumns when possible. - Always use
SET NOCOUNT ONat the beginning of Stored Procedures. - Replace
NTEXT,TEXT, andIMAGEwithNVARCHAR(MAX)andVARBINARY(MAX). - Consider using Table Variables instead of Temporary Tables when appropriate.
- Do not use
DATETIMEas aPRIMARY KEY. - Prefer
CHECK CONSTRAINTover Triggers for enforcing rules. - Keep Trigger logic minimal to reduce overhead.
- Avoid using
ROLLBACKin Triggers whenever possible. - Avoid using
SELECT INTOfor creating temporary tables unless necessary.
Stored Procedure Performance Tips
- Do not prefix Stored Procedure names with
sp_.
This prefix is reserved for system procedures, and SQL Server will first search in themasterdatabase, causing a performance hit. - Instead of placing multiple queries inside a single Stored Procedure, consider splitting them into separate procedures and calling them as needed.
Reason:
SQL Server caches execution plans per query. If a procedure contains multiple queries, it may be recompiled more often, reducing performance.
Each Stored Procedure is compiled once, and its Execution Plan is reused, improving performance.
Additional Notes:
- Use
SET NOCOUNT ON
Prevents sending the number of affected rows to the client, reducing network traffic. - Keep Stored Procedures small and focused
This reduces locking and improves performance. - Avoid dynamic SQL when possible
Static queries benefit more from execution plan caching. - Use
WITH RECOMPILEwhen necessary
Useful when query parameters vary significantly and cached plans are inefficient. - Allow users to cancel long operations
Avoid forcing system restarts due to unresponsive queries. - Handle optional parameters carefully
Use conditional logic (IF...ELSE) to generate efficient execution paths.
/