Wednesday, September 14, 2011

Find Index fragmentation for each index on a table in a DB

The following query will give out the fragmentation percentage for each index on a table in DB.


SELECT DISTINCT * FROM( SELECT  DB_NAME(ps.database_id) AS DBName
,OBJECT_NAME(ps.OBJECT_ID) AS TabeName
,ps.index_id
,b.name
,b.type_desc 
,ps.avg_fragmentation_in_percent
      FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, NULL) AS ps
     INNER JOIN sys.indexes AS b 
     ON ps.OBJECT_ID = b.OBJECT_ID
    AND ps.index_id         =  b.index_id
    WHERE ps.database_id = DB_ID()
          )A
ORDER BY a.avg_fragmentation_in_percent DESC






Friday, September 9, 2011

Very good article about datacompression

http://msdn.microsoft.com/en-us/library/dd894051(v=sql.100).aspx

Handling Deadlocks

"A deadlock occurs when two or more tasks permanently block each other by each task having a lock on a resource which the other tasks are trying to lock [msdn]" 


When SQL Server detects a deadlock between two tasks, it will terminate one of the tasks. We don't know which task would be terminated by SQL Server. It will have its own computations. What if we don't want one of the tasks to be a victim of dead lock? (Victim is the task that will be terminated by SQL Server). The following steps helps to prioritize the deadlock. There is a keyword



SET DEADLOCK_PRIORITY. We can use this property at the start of transaction or a task. It takes in following values. LOW/NORMAL/HIGH/ -10 to 10
Syntax: SET DEADLOCK_PRIORITY HIGH
Consider there are two tasks/Connections T1 and T2 and these will be dead locked. Normally when you run the two connections, connection1 with Task T1 becomes a victim. But, you want T2 to be the victim. If you don't want task T1 to be a victim, Set the DEADLOCK_PRIORTY greater than the DEADLOCK_PRIORITY of Task T2 .
IN T1 at the top of the query
SET DEADLOCK_PRIORITY NORMAL
GO
IN T2 at the top of the query
SET DEADLOCK_PRIORITY HIGH
GO
Now open two connections and run the queries. T2 will be a victim.

Using the concept of Unpivot

Pivoting and Unpivoting are a very handy features in SQL Server. Unpivoting technique in particular is very handy. Consider an example. Say there is an employee table that has ID,Name,Homeph,MobilePh,Workph fields in the table and there are more than 100 million records. Now a new requirement comes in to add the Faxnumber also. What are the options we have? One is using native ALTER TABLE statement and add the new field.

ALTER TABLE Employee
ADD Faxnum VARCHAR(13)

100 million records, its ok to alter the table. What if there are a billion records and a requirement comes in to add another field say ManagerPh? Again we have to alter the table. The best way to handle these kinds of situations is to use UNPIVOT. Look at the pattern. HomePh,MobilePh,Workph,FaxNum... all are of similar type (Phone numbers). The table can be called as PIVOTED (remember its just an example. to pivot the data we need to USE aggregate functions on one of the filed. Its just for understanding).

We can Unpivot. Create a table Employee with Fields ID,PhoneType, Number
Now we can use UNPIVOT or alternate way is to use Union/UnionAll

Using UNPIVOT:

SELECT ID,PhoneType,Number
FROM Employee
UNPIVOT(Number FOR PhoneType IN(HomePh,MobilePh,Workph)) UNP

This will change the fields to records. So, If at all new phone type needs to be added, there is no need to change the schema of the table. We just need to update the query.

Using UNION ALL

SELECT ID, 'HomePh' AS PhoneType, HomePh AS Number
UNION ALL
SELECT ID, 'MobliePh',MobilePh
UNION ALL
SELECT ID, 'WorkPh',WorkPh

The above UNION ALL statement is same as using UNPIVOT. I used UNION ALL here. UNION also can be used. Logically, UNION will do a DISTINCT on select columns. This decreases the performance. This is very true if the table holds huge amounts of data.