Showing posts with label SQL Server. Show all posts
Showing posts with label SQL Server. Show all posts

Monday, 19 March 2012

What about my indexes?

No need to say that indexes on tables are important, as they directly affect the performance of your queries and data applications.
Therefor it is also needless to say that maintenance of indexes is as important as a good indexing strategy. About indexing strategies, there are already written thousands and thousands of pages, and it is for this reason that I want t spend a few lines on index fragmentation and usage. So,what about my indexes, how much are they fragmented, are they used at all?
First, a script is shown below, which will give you a result set, showing the indexes and their usage statistics:  
SELECT  TableName = t.name,
                 [RowCount] = si.rows ,
                 IndexName  = ISNULL(i.name, i.type_desc),
                 IndexType  = ISNULL(i.type_desc, ''),
                 IsFilteredIndex = CASE WHEN i.has_filter != 0 THEN 'True' ELSE 'False' END,
                 Filter  = ISNULL(i.filter_definition , ''),
                 [FillFactor] = i.fill_factor,
                 [IndexDepth] = s.index_depth,
                 [FragmentationPercentage] =  ISNULL(CAST(s.avg_fragmentation_in_percent AS DECIMAL(10,2)),0),
                 [FragmentCount] = ISNULL(s.fragment_count,0),
                 [FragmentationSizeInPages] = ISNULL(CAST(s.avg_fragment_size_in_pages AS DECIMAL(10,2)),0),
                 [PageCount] = ISNULL(s.page_count,0),
                 UserSeeks = ISNULL(us.user_seeks,0),
                 UserScans = ISNULL(us.user_scans,0),
                 UserLookups = ISNULL(us.user_lookups,0),
                 UserUpdates = ISNULL(us.user_updates,0),
                 LastUserSeek = us.last_user_seek,
                 LastUserScan = us.last_user_scan,
                 LastUserLookup = us.last_user_lookup,
                 LastUserUpdate = us.last_user_update      
FROM    sys.tables t
INNER JOIN sysindexes si  ON si.id = t.object_id
INNER JOIN sys.indexes i  ON i.object_id=  t.object_id
LEFT JOIN sys.dm_db_index_physical_stats(DB_ID(),0,-1,0, null) s
                                                            ON s.object_id = i.object_id
                                                            AND s.index_id = i.index_id
LEFT JOIN sys.dm_db_index_usage_stats us
                                                            ON us.index_id = i.index_id
                                                            AND us.object_id = i.object_id
                                                            AND us.database_id = DB_ID()
WHERE    t.name NOT LIKE '%_tracking'
         AND t.name NOT IN  ('anchor' ,'scope_config' , 'scope_info', 'schema_info')
         AND      si.name LIKE 'PK_%'
         AND i.type_desc NOT LIKE 'HEAP'
ORDER BY t.name ASC, i.name ASC
Secondly, the following script will generate a result set, showing you the index fragmentation:
SELECT  DISTINCT
               SchemaName = s.name,
               TableName = t.name ,
               IndexName = i.Name,
               Fragmentation = ps.avg_fragmentation_in_percent
FROM    sys.dm_db_index_physical_stats(DB_ID(),0,-1,0, null) ps
INNER JOIN sys.tables t ON t.object_id = ps.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes  i ON i.index_id = ps.index_id
                                               AND i.object_id = t.object_id
WHERE   ps.avg_fragmentation_in_percent > 5
        AND     t.type = 'U' AND i.type <> 0
ORDER BY t.name;
Thirdly, a script will generate T-SQL code, which will allow you to either rebuild or reorganize, based on a 30% fragmentation ration to rebuild. This means that every index which is fragmented more than 30% should be rebuild, all others should be reorganized.
DECLARE @SQL NVARCHAR(2000);
DECLARE  @SchemaName NVARCHAR(10),
                 @TableName NVARCHAR(255),
                 @IndexAction NVARCHAR(20)

DECLARE IndexingCursor CURSOR FOR
SELECT   DISTINCT
                 SchemaName = s.name,
                 TableName = t.name ,
                 IndexAction = CASE        WHEN ps.avg_fragmentation_in_percent > 30 THEN 'REBUILD'
                                                            WHEN ps.avg_fragmentation_in_percent <= 30 THEN 'REORGANIZE'
                                             END
FROM    sys.dm_db_index_physical_stats(DB_ID(),0,-1,0, null) ps
INNER JOIN sys.tables t ON t.object_id = ps.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes  i ON i.index_id = ps.index_id
                                                     AND i.object_id = t.object_id
WHERE    ps.avg_fragmentation_in_percent > 5
         AND      t.type = 'U' AND i.type <> 0
ORDER BY t.name;

OPEN IndexingCursor;

FETCH NEXT FROM IndexingCursor
INTO @SchemaName, @TableName, @IndexAction;

WHILE @@FETCH_STATUS = 0
BEGIN
         PRINT  '/* Index maintenance for [' + DB_NAME() +'].[' + @SchemaName + '].[' + @TableName + '] */'
         PRINT 'ALTER INDEX ALL ON [' + DB_NAME() +'].[' + @SchemaName + '].[' + @TableName + '] ' + @IndexAction + ';'
         PRINT 'UPDATE STATISTICS [' + DB_NAME() +'].[' + @SchemaName + '].[' + @TableName + '];'
        
         FETCH NEXT FROM IndexingCursor
         INTO @SchemaName, @TableName, @IndexAction;

END


CLOSE IndexingCursor
DEALLOCATE IndexingCursor

Have fun!
Jurgen

Friday, 4 November 2011

A view on storing file data in SQL Server

Storing file data (BLOBs) (eg. pdf, word, excel ...) in SQL server always has been some kind of dark magic to a lot of people.

Before SQL Server 2008 we could store the BLOB data in VARBINARY(MAX) datatypes, in which you also had to convert the BLOB data into the binary format yourself ...


With SQL 2008, the FILESTREAM datatype was introduced. FILESTREAM enables us to integrate SQL Server with the NTFS file system ... BLOBs are stored as real files on the file system.

More on FILESTREAM: http://msdn.microsoft.com/en-us/library/bb933993.aspx




--Enable FILESTREAM
EXEC sp_filestream_configure @enable_level = 3;

--CREATE THE TABLE
CREATE TABLE TestFS
      (
            ID INT IDENTITY(1,1),
            FileName NVARCHAR(200),
            Content VARBINARY(MAX) FILESTREAM
      )


As from the new version of SQL Server, SQL 2012 (aka 'Denali'), a new feature has been introduced ... FILETABLE, based on the existing FILESTREAM feature in SQL Server. In fact, the FILETABLE feature is nothing more than storing files in special filetables in SQL server, but you will be able to access them from the file system. It is said that FILETABLE will be the next generation of FILESTREAM ...

More on FILETABLE: http://msdn.microsoft.com/en-us/library/ff929144(v=sql.110).aspx



--Create the table
CREATE TABLE DocumentStore AS FILETABLE
    WITH (
          FileTable_Directory = 'DocumentTable'
          FileTable_Collate_Filename = database_default
         );
GO
Have fun
Jurgen













Thursday, 15 September 2011

SQL Server Denali - LAG and LEAD




This is a short post on 2 new T-SQL features called LAG and LEAD, they are kind like Bonny & Clyde, they are mentioned in the same phrase...

LAG and LEAD accesses the data from respectively the previous and the next row in a table without using self joins.

Syntax:


LAG (scalar_expression [,offset] [,default])
OVER ( [ partition_by_clause ] order_by_clause )


LEAD (scalar_expression [ ,offset ] , [ default ] )
OVER ( [ partition_by_clause ] )

USE
AdventureWorks2008R2

GO

SELECT TerritoryName, BusinessEntityID, SalesYTD,
       LAG (SalesYTD, 1, 0) OVER (PARTITION BY TerritoryName ORDER BY SalesYTD DESC) AS PrevRepSales
FROM Sales.vSalesPerson
WHERE TerritoryName IN (N'Northwest', N'Canada')
ORDER BY TerritoryName;




SELECT BusinessEntityID, YEAR(QuotaDate) AS SalesYear, MONTH(QuotaDate) AS SalesMonth, SalesQuota AS CurrentQuota, LEAD(SalesQuota, 1,0) OVER (ORDER BY YEAR(QuotaDate), MONTH(QuotaDate)) AS NextQuota
FROM Sales.SalesPersonQuotaHistory
WHERE BusinessEntityID = 275 and YEAR(QuotaDate) IN ('2005','2006');


Have Fun!

Tuesday, 19 July 2011

New Date and Time functions in "Denali" CTP3

I've been playing around with the CTP3 of Denali and stumbled upon some new functions...
The new functions are :
  •  DATEFROMPARTS(@year, @month, @day)
    • returns a DATE value
  • DATETIMEFROMPARTS(@year, @month, @day, @hour, @minute, @seconds, @milliseconds) 
    • returns a DATETIME value
  •  TIMEFROMPARTS(@hour, @minute, @seconds, @fractions, @precision) 
    • returns a TIME value
    • where @fractions is an integer expression and @precision is an integer literal specifying the precision of the time value to be returned.)
    •   @fractions depend on @precision eg if the precision is 7 then each fraction represents 100 nanoseconds.
Remarks:
  • If the arguments are invalid, then an error is raised
  • If any of the parameters are null, null is returned
Some Examples:

SELECT DATEFROMPARTS(2011, 07, 20) AS 'Todays Date'

SELECT DATETIMEFROMPARTS (2011, 07, 20, 09, 51, 07, 321) AS 'Todays Date and Time'

SELECT TIMEFROMPARTS (09, 51, 07, 321 , 3) AS 'Todays Time'

have fun,
Jurgen

Thursday, 21 April 2011

Execute a stored procedure on SQLServer Startup

For a project we needed to run some T-SQL scripts when the SQL Express Database Engines on the client machines started (we need to have data available offline).
To get the job done,  SQL Server has the possibility to execute a stored procedure at it's startup.

For this you will need to execute:

1: sp_procoption  @ProcName  =  'stored procedure name',  
2:               @OptionName  =  'startup',  
3:               @OptionValue  = 'on'  
4: 

To turn it off again: 
1: sp_procoption  @ProcName  =  'stored procedure name',  
2:               @OptionName  =  'startup',  
3:               @OptionValue  = 'off'  
4: 


To see which procedures will be executed at startup:

1: SELECT  Name  
2: FROM  sysobjects   
3: WHERE  objectproperty(id, 'ExecIsStartup' )  =  1
4: 

Have fun
J.