Apply proper indexing in the table columns in the database
- Make sure that every table in your database has a primary key.
This will ensure that every table has a clustered index created (and hence, the corresponding pages of the table are physically sorted in the disk according to the primary key field). So, any data retrieval operation from the table using the primary key, or any sorting operation on the primary key field or any range of primary key values specified in the where clause will retrieve data from the table very fast.
Create non-clustered indexes on columns which are
Frequently used in the search criteria.
Used to join other tables.
Used as foreign key fields.
Of having high selectivity (column which returns a low percentage (0-5%) of rows from a total number of rows on a particular value).
Used in the ORDER BY clause.
Don't use "SELECT*" in a SQL query
Unnecessary columns may get fetched that will add expense to the data retrieval time.
The database engine cannot utilize the benefit of "Covered Index" and hence the query performs slowly.
Example:
SELECT Cash, Age, Amount FROM Investments;
Instead of:
SELECT * FROM Investments;
Try to avoid HAVING Clause in Select statements
HAVING clause is used to filter the rows after all the rows are selected and is used like a filter. Try not to use HAVING clause for any other purposes.
Example:
SELECT Name, count (Name) FROM Investments WHERE Name!= ‘Test’ AND Name!= ‘Value’ GROUP BY Name;
Instead of:
SELECT Name, count (Name) FROM Investments GROUP BY Name HAVING Name!= ‘Test’ AND Name!= ‘Value’ ;
Try to minimize number of sub query blocks within a query
Sometimes we may have more than one sub query in our main query. We should try to minimize the number of sub query block in our query.
Example:
SELECT Amount FROM Investments WHERE (Cash, Fixed) = (SELECT MAX (Cash), MAX (Fixed) FROM Retirements) AND Goal = 1;
Instead of:
SELECT Amount FROM Investments WHERE Cash = (SELECT MAX (Cash) FROM Retirements) AND Fixed = (SELECT MAX (Fixed) FROM Retirements) AND Goal = 1;
Avoid unnecessary columns in the SELECT list and unnecessary tables in join conditions
Selecting unnecessary columns in a Select query adds overhead to the actual query, especially if the unnecessary columns are of LOB types.
Including unnecessary tables in join conditions forces the database engine to retrieve and fetch unnecessary data and increases the query execution time.
Do not use the COUNT() aggregate in a subquery to do an existence check
When you use COUNT(), SQL Server does not know that you are doing an existence check. It counts all matching values, either by doing a table scan or by scanning the smallest non-clustered index.
When you use EXISTS, SQL Server knows you are doing an existence check. When it finds the first matching value, it returns TRUE and stops looking.
Try to avoid joining between two types of columns
When joining between two columns of different data types, one of the columns must be converted to the type of the other. The column whose type is lower is the one that is converted.
If you are joining tables with incompatible types, one of them can use an index, but the query optimizer cannot choose an index on the column that it converts.
Try not to use COUNT(*) to obtain the record count in a table
To get the total row count in a table, we usually use the following Select statement:
SELECT COUNT(*) FROM [dbo].[PercentageForGoal]
This query will perform a full table scan to get the row count.
The following query would not require a full table scan. (Please note that this might not give you 100% perfect results always, but this is handy only if you don't need a perfect count.)
SELECT rows FROM sysindexes
WHERE id = OBJECT_ID('[dbo].[PercentageForGoal]') AND indid< 2
Try to use operators like EXISTS, IN and JOINS appropriately in your query
- Usually IN has the slowest performance.
- IN is efficient, only when most of the filter criteria for selection are placed in the sub-query of a SQL statement.
- EXISTS is efficient when most of the filter criteria for selection is in the main query of a SQL statement.
Try to avoid dynamic SQL
Unless really required, try to avoid the use of dynamic SQL because:
Dynamic SQL is hard to debug and troubleshoot.
If the user provides the input to the dynamic SQL, then there is a possibility of SQL injection attacks.
Try to avoid the use of temporary tables
Unless really required, try to avoid the use of temporary tables. Rather use table variables.
In 99% of cases, table variables reside in memory, hence it is a lot faster. Temporary tables reside in the TempDb database. So operating on temporary tables require inter database communication and hence will be slower.
Instead of LIKE search, use full text search for searching textual data
Full text searches always outperform LIKE searches.
Full text searches will enable you to implement complex search criteria that can't be implemented using a LIKE search, such as searching on a single word or phrase (and optionally, ranking the result set), searching on a word or phrase close to another word or phrase, or searching on synonymous forms of a specific word.
Implementing full text search is easier to implement than LIKE search (especially in the case of complex search requirements).
Try to use UNION to implement an "OR" operation
Try not to use "OR" in a query. Instead use "UNION" to combine the result set of two distinguished queries. This will improve query performance.
Better use UNION ALL if a distinguished result is not required. UNION ALL is faster than UNION as it does not have to sort the result set to find out the distinguished values.
Implement a lazy loading strategy for large objects
Store Large Object columns (like VARCHAR(MAX), Image, Text etc.) in a different table than the main table, and put a reference to the large object in the main table.
Retrieve all the main table data in a query, and if a large object is required to be loaded, retrieve the large object data from the large object table only when it is required.
Implement the following good practices in User Defined Functions
Do not call functions repeatedly within your Stored Procedures, triggers, functions, and batches. For example, you might need the length of a string variable in many places of your procedure, but don't call the LEN function whenever it's needed; instead, call the LEN function once, and store the result in a variable for later use.
Implement the following good practices in Triggers
- Try to avoid the use of triggers. Firing a trigger and executing the triggering event is an expensive process.
- Never use triggers that can be implemented using constraints.
- Do not use the same trigger for different triggering events (Insert, Update and Delete).
- Do not use transactional code inside a trigger. The trigger always runs within the transactional scope of the code that fires the trigger.