Top Banner

of 25

Best SQL Practices on Performance

Jun 02, 2018

Download

Documents

Prabu Jothi
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
  • 8/10/2019 Best SQL Practices on Performance

    1/25

    Performance Tuning & Maintenance Document Page 1 of 25

    Performance Tuning

    DB SQL Server 2008 R2

    &

    DB Maintenance Document

  • 8/10/2019 Best SQL Practices on Performance

    2/25

  • 8/10/2019 Best SQL Practices on Performance

    3/25

    Performance Tuning & Maintenance Document Page 3 of 25

    Table of Contents

    1 DB PERFORMANCE TUNING GUIDELINES ....................................................................................................... 4

    2 CHECKLIST FOR ANALYZING SLOW-RUNNING QUERIES ............................................................................... 11

    3 SQL MAINTENANCE ACTIVITY ...................................................................................................................... 12

    3.1 TO CHECK THE MEMORYSTATUS ........................................................................................................................ 12 3.2 TO CHECK THE UNUSED CACHE........................................................................................................................... 12 3.3 TO PULL THE PHYSICAL MEMORY& SERVER INFORMATION....................................................................................... 12 3.4 TO CALCULATE THETPM .................................................................................................................................. 12 3.5 TO CHECK THE CURRENT CONCURRENT USERS(PROCESSES AT THAT TIME). ................................................................. 13 3.6 TO CHECK THERAM MEMORY .......................................................................................................................... 13 3.7 TO IDENTIFICATION OF UNUSEDINDEX................................................................................................................. 14 3.8 DRIVENQ UERIES(SAMPLE) ............................................................................................................................... 15 3.9 TABLEBUFFERUSAGE ...................................................................................................................................... 15

    3.10 RE-INDEXING.................................................................................................................................................. 17 3.11 REBUILD THEINDEX ......................................................................................................................................... 18 3.12 SCRIPTS FORDEFRAGMENTATION OF THEINDEX .................................................................................................... 19 3.13 SCRIPTS FOR GENERATINGDROP & CREATEINDEX ................................................................................................. 21 3.14 TO GET THE AGGREGATE PERFORMANCE STATISTICS FROMPLANCACHE..................................................................... 24

  • 8/10/2019 Best SQL Practices on Performance

    4/25

    Performance Tuning & Maintenance Document Page 4 of 25

    1 DB Performance Tuning Guidelines

    1. Do not use OPENROWSET and OLEDB command anywhere in the SQL code.

    2. For the bulk column fetch, first retrieve the main field based on the different condition and thenfetch all required columns based on the derived main fields.

    a. E.g. In field status, first fetch the Work Orders & then fetch the details of Work Ordersb. Similarly, fetch the Job Id first in Technician Job Details & then fetch all the other

    columns based on the Job id which was retrieved initially.

    3. Always do not fetch all the grids in a screen. Analyse the screen and based on the result,proceed for coding

    a. E.g. In field status, there are three grids where we can display the output for

    1. Job Summary2. List View3. Total Count

    b. In this case, Job Summary & Total Count output s will not vary unless we modify themain input filter conditions.

    c. For sorting any columns in the list view, we should not load the Job Summary & TotalCount columns again, since they would have loaded already. (UI changes are needed)

    d. Based on the sorting, we can load only the List view.

    4. Avoid unwanted where condition while framing SQL Query dynamicallya. E.g, if the Order Date input is passed as NULL, then we should not send any filter for

    Order Date.

    Donts: and wo.priority_id = isnull(pi_priority_id,wo.priority_id)

    Dos: if @pi_priority_id is not nullbegin

    select @l_str = @l_str + ' and wo.priority_id ='+convert(nvarchar(200),@pi_priority_id) +' '

    end

    5. Do not use functions in the left side of the where conditiona. E.g. where isnull(order_date,) between @pi_start and @pi_end b. where cast(order_date as date) between @pi_start and @pi_endc. where dbo.fn_Xdate(order_date) between @pi_start and @pi_end

  • 8/10/2019 Best SQL Practices on Performance

    5/25

    Performance Tuning & Maintenance Document Page 5 of 25

    6. All the images should be stored in Fileserver / Filestream. Also it would be better if it is readfrom UI side.

    7. Avoid using functions in where clause.Donts: and isnull(reviewer_id,0) = isnull(@pi_reviewer_id,0)

    Dos: and (reviewer_id is not null and reviewer_id = isnull(@pi_reviewer_id,0))

    8. Join the different tables based on the volume from small to largeDonts:

    from #Work_order_Result wo join work_order wo1 (nolock) on wo1.work_order_id= wo.work_order_id

    Dos:

    From #work_order_result wo join work_order wo1 (nolock) on wo.work_order_id= wo1.work_order_id

    9. In a Join, keep inner join first, after that keep all the left join , It will reduce the IO Reads.Dont s:

    from #Work_order_Result wo1

    Join ref_work_item_type rwit (nolock)on rwit.work_item_type_id = wo1.work_item_type_id

    left join ref_organization ro (nolock) on ro.id_org = wo1.vendor_idleft join ref_priority rp (nolock) on rp.priority_id= wo1.priority_id join vw_property_details re on re.Property_Id = wo1.Property_Id

    Dos:

    from #Work_order_Result wo1Join ref_work_item_type rwit (nolock)

    on rwit.work_item_type_id = wo1.work_item_type_id

    join vw_property_details re on re.Property_Id = wo1.Property_Idleft join ref_organization ro (nolock) on ro.id_org = wo1.vendor_idleft join ref_priority rp (nolock) on rp.priority_id= wo1.priority_id

    10. Use Nolock for well known masters for fetching stored procedures.Dont s:

  • 8/10/2019 Best SQL Practices on Performance

    6/25

    Performance Tuning & Maintenance Document Page 6 of 25

    from #Work_order_Result wo1 join ref_priority rp on rp.priority_id= wo1.priority_id join vw_property_details re on re.Property_Id = wo1.Property_Id

    Dos:

    from #Work_order_Result wo1 join ref_priority rp (nolock) on rp.priority_id= wo1.priority_id join vw_property_details re (noexpand) on re.Property_Id= wo1.Property_Id

    11. Use Periodic Index, instead of reindex. With the help of Show Index Statistics, we should useindex defragment.

    Eg:USE FPREO;

    GODBCC SHOW_STATISTICS ("ref_meta_data", pk_ref_meta_data_meta_data_id);

    12. Always use covering index for non-clustered index.

    Donts: CREATE NONCLUSTERED INDEX IX_OrderDetailDateProdSold ON dbo.OrderDetail( ProductID, OrderDate)

    Dos: CREATE NONCLUSTERED INDEX IX_OrderDetailDateProdSold ON dbo.OrderDetail( ProductID, OrderDate) INCLUDE (QtySold);

    13. If there is an index for any column, then check whether the read and write process areperformed by the respective index. It the read process does not happen for a long period, thenwe do not need that index.

    14. Try to have views for addresses, since we need to map many tables to fetch the address invarious queries. Please create an index for the respective views.

    15. Also try to have views for Job details like Category, Service Type, Service Request in order toavoid the joins for different tables in many queries.

    16. Test every Execute Statements with the option with recompile

    Eg: exec get_record_search_list_FS @pi_sp_name=N'[get_order_status]',

  • 8/10/2019 Best SQL Practices on Performance

    7/25

    Performance Tuning & Maintenance Document Page 7 of 25

    @sp_in_params=N'"null~null~null~null~null~null~null~null~null~Null~Null~Null~0, 5, 11, 12, 7,4, 3, 2, 6, 9, 47, 8, 10~4~Null~null~null~null~1~null~null~null~1~Null~1~1"'With Recompile

    17. For every SP execution time , we need to verify the IO. Depending upon the IO , CPU Utilizationwill differ.Ex: Set Statistics IO on

    EXEC SP Name Set Statistics IO OFF

    Logical read should be always less. Index for specific columns will help to reduce logicalReads.

    18. If a condition contains OR , then put that condition firsta. Where (wa.tech_id = @pi_tech_id or @pi_login_id = 1)

    b. Please do write the above code as where (@pi_login_id = 1 or wa.tech_id =@pi_tech_id)

    19. If N select queries are mentioned in a SP, try to convert all the select queries into different SPs.

    20. Remove Not in condition from all coding. Donts: and state_id not in (31,32,33,34)

    Dos: and state_id in (25,26,27,28)

    21. Avoid use distinct key word

    22. Create a function with SCHEMABINDING Ex:

    CREATE FUNCTION SchemaBinded ( @INPUT INT )RETURNS INT WITH SCHEMABINDINGBEGIN

    RETURN @INPUT * 2 + 50ENDGO

    http://www.mssqltips.com/sqlservertip/1692/using-schema-binding-to-improve-sql-server-udf-performance/

    23. To Reduce the IO of each stored procedures with the help of user defined function (useComputed Columns /persisted Columns )

    http://www.mssqltips.com/sqlservertip/1692/using-schema-binding-to-improve-sql-server-udf-http://www.mssqltips.com/sqlservertip/1692/using-schema-binding-to-improve-sql-server-udf-
  • 8/10/2019 Best SQL Practices on Performance

    8/25

    Performance Tuning & Maintenance Document Page 8 of 25

    Ex: alter table work_order add wo_category_id as [dbo] . [fn_wo_category_id] ( work_order_id ) persistedgo

    alter table work_order add wo_category_id as [dbo] . [fn_wo_category_id] ( work_order_id )go - this is better than the above persited column

    It will help to avoid Demoralization of the table.

    24. Without Group by we will be able to get the No. of records count(*) Usingcount(*) over( partition by (select 1)) as Total_Count

    Record Count in the specific select statement itself.

    25. XML is always faster than the CSV command. It will not have parsing methodology.

    Ex: declare @l_category nvarchar ( max )

    select @l_category = substring ( category , 1 , len ( category ) - 1 )

    from (select

    ( select convert ( nvarchar ( 1000 ), wj1 . work_order_category_id ) + ','

    from dbo . wo_job wj1 ( nolock )where wj1 . work_order_id = wj . work_order_id

    order by work_order_idfor xml path ( '' ) ) as category

    from dbo . wo_job wjwhere work_order_id = @pi_work_order_id

    ) a

    26. Always use EXISTS query instead of NOT EXISTS.

    Donts: and not exists( select 1 from work_order wo1 ( nolock )

    where wo . work_order_id = wo1 . work_order_idand wo1 . reviewer_id = @pi_login_id

    )

    Dos: and exists( select 1 from work_order wo1 ( nolock )

    where wo . work_order_id = wo1 . work_order_idand wo1 . reviewer_id = @pi_login_id )

    27. If temporary tables are used in stored procedures, then drop temp table at the end of the sp.

    Ex:

  • 8/10/2019 Best SQL Practices on Performance

    9/25

    Performance Tuning & Maintenance Document Page 9 of 25

    IF OBJECT_ID ( 'tempdb..#temp_login' ) IS NOT NULL DROP TABLE #temp_login

    28. Avoid using sub queries / joins with the same table in a stored procedure . Instead use EXISTSwhich will improve the performance drastically.

    Donts: join ref_property re (nolock)join ref_property re1 (nolock) on re1.property_id= re.property_idand re1.property_stage_id in (1,2)where re.property_id = @pi_property_id

    Dos: join ref_property re ( nolock ) where re.property_id = @pi_property_idand exists ( select 1 ref_property re1 ( nolock )

    where re1 . property_id = re . property_idand re1 . property_stage_id in ( 1 , 2 )

    )

    29. Avoid using global temporary ##temp table s in a stored procedures. It will not support whenconcurrent users perform simultaneously. i.e., same value will be passed to all users which leadsto wrong data entry.

    Donts: create table ##temp( sl_no int identity ( 1 , 1 ),

    property_id int )

    Dos: create table #temp( sl_no int identity ( 1 , 1 ),

    property_id int )

    30. Avoid using SELECT INTO keyword for creating temp tables. Instead, create a temporary tableand then insert the records.

    Donts: Select id,designation

    into #tempfrom ref_designationwhere is_active = 1

    Dos: Create table #temp (id bigint, designation nvarchar(400))

  • 8/10/2019 Best SQL Practices on Performance

    10/25

    Performance Tuning & Maintenance Document Page 10 of 25

    Insert into #temp (id, desigantion)Select id,designation from ref_designation (nolock) where is_active = 1

    IF OBJECT_ID ( 'tempdb..#temp' ) IS NOT NULL DROP TABLE #temp

    31. While insertion, use column list in the insert statement. It will avoid unwanted errors when anew column is added in the specified table.

    Donts: Insert into #tempSelect work_order_id, work_order_status_work_item_typefrom work_order where work_order_id = @pi_work_order_id

    Dos: Insert into #temp (work_order_id, work_order_status_work_item_type)Select work_order_id, work_order_status_work_item_typefrom work_order (nolock) where work_order_id = @pi_work_order_id

    32. Use NOEXPAND keyword, when views are used in joins.

    EX:from #Work_order_Result wo1

    join ref_priority rp (nolock) on rp.priority_id= wo1.priority_id join vw_property_details re (noexpand) on re.Property_Id= wo1.Property_Id

    33. Avoid selecting records by using * keyword in stored procedures. Instead, provide the columnlist which needs to be given as output.

    Donts: Select * from ref_property (nolock) where property_id = @pi_property_id

    Dos: Select property_id, property_code, property_number,priority_id,is_activefrom ref_property (nolock) where property_id = @pi_property_id

    34. Instead of including Nolock for all the tables in the stored procedure, we can set the isolation levelas SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED in the top of stored procedures.

  • 8/10/2019 Best SQL Practices on Performance

    11/25

    Performance Tuning & Maintenance Document Page 11 of 25

    It will play the exact role of Nolock .It refers all the tables which referred in the respective storedprocedure. It would be applicable for the connections (Session ID) even though the respective Storedprocedures contains the nested Stored procedures/Remote Procedure. This should applicable for onlyfetch stored procedures.

    2 Checklist for Analyzing Slow-Running Queries

    Slow network communication. Inadequate memory in the server computer, or not enough memory available for SQL Server. Lack of useful statistics Lack of useful indexes. Lack of useful indexed views. Lack of useful data striping. Lack of useful partitioning.

    Reference: http://msdn.microsoft.com/en-us/library/ms177500.aspx

    http://msdn.microsoft.com/en-us/library/ms177500.aspxhttp://msdn.microsoft.com/en-us/library/ms177500.aspxhttp://msdn.microsoft.com/en-us/library/ms177500.aspxhttp://msdn.microsoft.com/en-us/library/ms177500.aspx
  • 8/10/2019 Best SQL Practices on Performance

    12/25

    Performance Tuning & Maintenance Document Page 12 of 25

    3 SQL Maintenance Activity

    3.1 To Check the memory Status

    DBCC MEMORYSTATUS

    3.2 To Check the unused cache

    DBCC FREESYSTEMCACHE ( 'ALL' ) WITH MARK_IN_USE_FOR_REMOVAL;

    3.3 To pull the physical memory & server information

    select * from sys . dm_os_sys_info

    select * from sys . dm_os_sys_memory

    select convert ( numeric ( 5 , 2 ),( total_physical_memory_kb / 1024.0 / 1024.0 )) as Total , convert ( numeric ( 5 , 2 ),( available_physical_memory_kb / 1024.0 / 1024.0 )) as Available, system_memory_state_desc ,( Select(( bpool_committed * 8 )/ 1024.0 / 1024.0 ) from sys . dm_os_sys_info ( nolock ) ) As SQLUseage from sys . dm_os_sys_memory ( nolock )

    3.4 To Calculate the TPM

    DECLARE @cntr_value1 bigint

    DECLARE @cntr_value2 bigint

    t:

    SELECT @cntr_value1 = cntr_value

    FROM sys . dm_os_performance_counters

    WHERE counter_name = 'transactions/sec'

    AND object_name = 'SQLServer:Databases'

  • 8/10/2019 Best SQL Practices on Performance

    13/25

    Performance Tuning & Maintenance Document Page 13 of 25

    AND instance_name = 'FPREOPRO'

    WAITFOR DELAY '00:00:01'

    SELECT @cntr_value2 = cntr_value

    FROM sys . dm_os_performance_counters

    WHERE counter_name = 'transactions/sec'

    AND object_name = 'SQLServer:Databases'

    AND instance_name = 'FPREOPRO'

    insert into mem_transaction_counter

    Select @cntr_value2 - @cntr_value1 , getdate ()

    goto t

    3.5 To check the current concurrent users (Processes at that time).

    select GETDATE() as 'Time' , COUNT(*) as 'Connection_count'from master . dbo . sysprocesses pjoin master . dbo . sysdatabases d on p . dbID = d . dbIDwhere p . dbid = db_id ()

    3.6 To check the RAM Memory

    SELECT GETDATE() As Time , physical_memory_in_bytes / 1073741824.0 as [Physical Memory_GB] FROM sys . dm_os_sys_info

  • 8/10/2019 Best SQL Practices on Performance

    14/25

    Performance Tuning & Maintenance Document Page 14 of 25

    3.7 To Identification of unused IndexScan: An index scan is a complete read of all of the leaf pages in the index.

    Seek: An index seeks is an operation where SQL uses the b-tree structure to locate either a specificvalue or the beginning of a range of value

    If both are 0 then the index is useless.

    1)WITH indexstats ( [Table] , [Index] , [Reads] , [Writes] , [Rows] ) AS ( SELECT usr . [name] + '.' + obj . [name] [Table] , ixs . [name] [Index] , usage . user_seeks + usage . user_scans + usage . user_lookups [Reads] , usage . [user_updates] [Writes] , ( SELECT SUM( sp . [rows] ) FROM sys . partitions spWHERE usage . OBJECT_ID = sp . object_id AND sp . index_id = usage . index_id )

    [Rows]FROM sys . dm_db_index_usage_stats usage INNER JOIN sys . indexes ixs ON usage . [object_id] = ixs . [object_id]AND ixs . [index_id] = usage . [index_id] INNER JOIN sys . objects obj ON usage . [object_id] = obj . [object_id]INNER JOIN sys . sysusers usr ON obj . [schema_id] = usr . [uid] WHERE usage . database_id = DB_ID () AND usage . index_id > 0 AND OBJECTPROPERTY( usage . [object_id] , 'IsUserTable' ) = 1 ) SELECT 'Drop Index ' +[INDEX] + ' on ' +[table] ,* FROM indexstats WHERE Reads = 0 and ( [index] not like '%pk_%' and [index] not like '%uk_%' ) ORDER BY [Rows] DESC, [Index]go

    2)DECLARE @dbid INTSELECT @dbid = DB_ID ( DB_NAME())SELECT OBJECTNAME = OBJECT_NAME( I . OBJECT_ID ),INDEXNAME = I . NAME,I . INDEX_IDFROM SYS. INDEXES IJOIN SYS. OBJECTS OON I . OBJECT_ID = O . OBJECT_IDWHERE OBJECTPROPERTY( O. OBJECT_ID , 'IsUserTable' ) = 1AND I . INDEX_ID NOT IN (SELECT S . INDEX_ID

    FROM SYS. DM_DB_INDEX_USAGE_STATS SWHERE S . OBJECT_ID = I . OBJECT_IDAND I . INDEX_ID = S . INDEX_IDAND DATABASE_ID = @dbid )ORDER BY OBJECTNAME,I . INDEX_ID ,INDEXNAME ASCGO

  • 8/10/2019 Best SQL Practices on Performance

    15/25

    Performance Tuning & Maintenance Document Page 15 of 25

    3.8 To Identification of Missing Index

    SELECT mid . statement , migs . avg_total_user_cost * ( migs . avg_user_impact / 100.0 ) * ( migs . user_seeks + migs . user_scans ) AS

    improvement_measure , OBJECT_NAME( mid . Object_id ), 'CREATE INDEX [idx_' + CONVERT ( varchar , mig . index_group_handle ) + '_' + CONVERT ( varchar , mid . index_handle ) + '_' +LEFT ( PARSENAME( mid . statement , 1 ), 32 ) + ']' + ' ON ' + mid . statement + ' (' + ISNULL ( mid . equality_columns , '' ) + CASE WHEN mid . equality_columns IS NOT NULL AND mid . inequality_columns IS NOT NULL THEN ',' ELSE '' END + ISNULL ( mid . inequality_columns , '' ) + ')' + ISNULL ( ' INCLUDE (' + mid . included_columns + ')' , '' ) AS create_index_statement , migs .*, mid . database_id , mid . [object_id] FROM sys . dm_db_missing_index_groups mig JOIN sys . dm_db_missing_index_group_stats migs ON migs . group_handle = mig . index_group_handle JOIN sys . dm_db_missing_index_details mid ON mig . index_handle = mid . index_handle WHERE migs . avg_total_user_cost * ( migs . avg_user_impact / 100.0 ) * ( migs . user_seeks + migs . user_scans ) > 10 ORDER BY migs . avg_total_user_cost * migs . avg_user_impact * ( migs . user_seeks + migs . user_scans )

    DESC

    3.9 Driven Queries (Sample)

    Optimize Parameter Driven Queries with SQL Server OPTIMIZE FOR Hint:

    DECLARE @Country VARCHAR( 20 )

    SET @Country = 'US'SELECT *

    FROM Sales.SalesOrderHeader h , Sales.Customer c ,Sales.SalesTerritory t

    WHERE h.CustomerID = c.CustomerIDAND c.TerritoryID = t.TerritoryIDAND CountryRegionCode = @Country

    OPTION ( OPTIMIZE FOR ( @Country = 'US' ))

    Reference for the above:http://www.mssqltips.com/sqlservertip/1354/optimize-parameter-driven-queries-with-sql-server-optimize-for-hint/

    3.10 Table Buffer Usage

    SELECT

    obj . [name] ,

    http://www.mssqltips.com/sqlservertip/1354/optimize-parameter-driven-queries-with-sql-server-optimize-for-hint/http://www.mssqltips.com/sqlservertip/1354/optimize-parameter-driven-queries-with-sql-server-optimize-for-hint/http://www.mssqltips.com/sqlservertip/1354/optimize-parameter-driven-queries-with-sql-server-optimize-for-hint/http://www.mssqltips.com/sqlservertip/1354/optimize-parameter-driven-queries-with-sql-server-optimize-for-hint/
  • 8/10/2019 Best SQL Practices on Performance

    16/25

    Performance Tuning & Maintenance Document Page 16 of 25

    i . [name] ,

    i . [type_desc] ,

    count (*) AS Buffered_Page_Count ,

    count (*) * 8192.0 / ( 1024 * 1024 ) as Buffer_MB

    FROM sys . dm_os_buffer_descriptors AS bd

    INNER JOIN

    (

    SELECT object_name ( object_id ) AS name

    , index_id , allocation_unit_id , object_id

    FROM sys . allocation_units AS au

    INNER JOIN sys . partitions AS p

    ON au . container_id = p . hobt_id

    AND ( au . type = 1 OR au . type = 3 )

    UNION ALL

    SELECT object_name ( object_id ) AS name

    , index_id , allocation_unit_id , object_id

    FROM sys . allocation_units AS au INNER JOIN sys . partitions AS p

    ON au . container_id = p . hobt_id

    AND au . type = 2

    ) AS obj

    ON bd . allocation_unit_id = obj . allocation_unit_id

    LEFT JOIN sys . indexes i on i . object_id = obj . object_id AND i . index_id =

    obj . index_id

    WHERE database_id = db_id ()

    GROUP BY obj . name , obj . index_id , i . [name] , i . [type_desc]

    ORDER BY Buffered_Page_Count DESC

  • 8/10/2019 Best SQL Practices on Performance

    17/25

    Performance Tuning & Maintenance Document Page 17 of 25

    3.11 Re-Indexing

    CREATE PROCEDURE upd_reindexASbeginset nocount on

    declare @po_error_code nvarchar ( 4000 ),@po_severity tinyint ,@l_incr int ,@l_count int ,@l_table_name nvarchar ( 200 )

    --if exists(select 1 from sys.tables where name = 'TableRowCount')

    --begin-- drop table [TableRowCount]--end

    --CREATE TABLE [TableRowCount](-- TableName sysname,-- [TableRowCount] int )

    ----EXEC sp_MSForEachTable 'INSERT [TableRowCount](TableName,[TableRowCount]) SELECT ''?'', COUNT(*) FROM ?'

    --EXEC sp_MSforeachtable @command1 = "print '?' DBCC DBREINDEX ('?', '', 80)"

    --EXEC sp_updatestats

    --select * from [TableRowCount]

    create table #temp_reindex(sl_no int ,table_name nvarchar ( 200 ))

    insert into #temp_reindex

    ( sl_no ,table_name

    )SELECT row_number () over ( order by name ),

    nameFROM sys . tableswhere type = 'U'

    if exists ( select 1 from #temp_reindex )

  • 8/10/2019 Best SQL Practices on Performance

    18/25

    Performance Tuning & Maintenance Document Page 18 of 25

    begin select @l_incr = 1

    select @l_count = COUNT(*) from #temp_reindex

    while @l_incr < = @l_countbegin

    select @l_table_name = table_name

    from #temp_reindex tpwhere sl_no = @l_incr

    PRINT 'Reindexing Table: ' + @l_table_nameDBCC DBREINDEX ( @l_table_name , '' , 80 )

    select @l_incr = @l_incr + 1

    select @l_table_name = null

    endend

    EXEC sp_updatestats

    set nocount offendgo

    3.12 Rebuild the Index

    create procedure rebuild_indexas begin DECLARE @Database VARCHAR( 255 ) DECLARE @Table VARCHAR( 255 ) DECLARE @cmd NVARCHAR( 500 ) DECLARE @fillfactor INT

    SET @fillfactor = 90

    DECLARE DatabaseCursor CURSOR FOR

    SELECT name FROM MASTER. dbo . sysdatabases WHERE dbid = db_id ()ORDER BY 1

    OPEN DatabaseCursor

    FETCH NEXT FROM DatabaseCursor INTO @DatabaseWHILE @@FETCH_STATUS = 0BEGIN

  • 8/10/2019 Best SQL Practices on Performance

    19/25

  • 8/10/2019 Best SQL Practices on Performance

    20/25

    Performance Tuning & Maintenance Document Page 20 of 25

    -- Declare a cursor.DECLARE tables CURSOR FOR

    SELECT TABLE_SCHEMA + '.' + TABLE_NAMEFROM INFORMATION_SCHEMA. TABLESWHERE TABLE_TYPE = 'BASE TABLE' ;

    -- Create the table.CREATE TABLE #fraglist (

    ObjectName char ( 255 ),ObjectId int ,IndexName char ( 255 ),IndexId int ,Lvl int ,CountPages int ,CountRows int ,MinRecSize int ,MaxRecSize int ,AvgRecSize int ,

    ForRecCount int ,Extents int ,ExtentSwitches int ,AvgFreeBytes int ,AvgPageDensity int ,ScanDensity decimal ,BestCount int ,ActualCount int ,LogicalFrag decimal ,ExtentFrag decimal );

    -- Open the cursor.OPEN tables ;

    -- Loop through all the tables in the database.FETCH NEXT

    FROM tablesINTO @tablename ;

    WHILE @@FETCH_STATUS = 0BEGIN-- Do the showcontig of all indexes of the table

    INSERT INTO #fraglistEXEC ( 'DBCC SHOWCONTIG (''' + @tablename + ''')

    WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS' );FETCH NEXT

    FROM tables

    INTO @tablename ;END;

    -- Close and deallocate the cursor.CLOSE tables ;DEALLOCATE tables ;

    -- Declare the cursor for the list of indexes to be defragged.DECLARE indexes CURSOR FOR

    SELECT ObjectName , ObjectId , IndexId , LogicalFrag

  • 8/10/2019 Best SQL Practices on Performance

    21/25

    Performance Tuning & Maintenance Document Page 21 of 25

    FROM #fraglistWHERE LogicalFrag >= @maxfrag

    AND INDEXPROPERTY ( ObjectId , IndexName , 'IndexDepth' ) > 0 ;

    -- Open the cursor.OPEN indexes ;

    -- Loop through the indexes.FETCH NEXT

    FROM indexesINTO @tablename , @objectid , @indexid , @frag ;

    WHILE @@FETCH_STATUS = 0BEGIN

    PRINT 'Executing DBCC INDEXDEFRAG (0, ' + RTRIM( @tablename ) + ',' + RTRIM( @indexid ) + ') - fragmentation currently '

    + RTRIM( CONVERT( varchar ( 15 ), @frag )) + '%' ;SELECT @execstr = 'DBCC INDEXDEFRAG (0, ' + RTRIM( @objectid ) + ',

    ' + RTRIM( @indexid ) + ')' ;

    EXEC ( @execstr );FETCH NEXT

    FROM indexesINTO @tablename , @objectid , @indexid , @frag ;

    END;

    -- Close and deallocate the cursor.CLOSE indexes ;DEALLOCATE indexes ;

    -- Delete the temporary table.DROP TABLE #fraglist ;end

    3.14 Scripts for generating Drop & Create Index

    SELECTixz . object_id ,tablename = QUOTENAME( scmz . name ) + '.' + QUOTENAME(( OBJECT_NAME( ixz . object_id ))),tableid = ixz . object_id ,indexid = ixz . index_id ,indexname = ixz . name ,isunique = INDEXPROPERTY ( ixz . object_id , ixz . name , 'isunique' ),isclustered = INDEXPROPERTY ( ixz . object_id , ixz . name , 'isclustered' ),indexfillfactor = INDEXPROPERTY ( ixz . object_id , ixz . name , 'indexfillfactor' ),--SQL2008+ Filtered indexes:CASE WHEN ixz . filter_definition IS NULL THEN '' ELSE ' WHERE ' + ixz . filter_definitionEND Filter_Definition

  • 8/10/2019 Best SQL Practices on Performance

    22/25

    Performance Tuning & Maintenance Document Page 22 of 25

    --For 2005, which did not have filtered indexes, comment out the aboveCASE statement, and uncomment this:INTO #tmp_indexesFROM sys . indexes ixzINNER JOIN sys . objects obzON ixz . object_id = obz . object_id INNER JOIN sys . schemas scmzON obz . schema_id = scmz . schema_id WHERE ixz . index_id > 0AND ixz . index_id < 255 ---- 0 = HEAP index, 255 = TEXT columns indexAND INDEXPROPERTY ( ixz . object_id , ixz . name , 'ISUNIQUE' ) = 0 -- comment outto include unique andAND INDEXPROPERTY ( ixz . object_id , ixz . name , 'ISCLUSTERED' ) = 0 -- commentout to include PK's

    ALTER TABLE #tmp_indexes ADD keycolumns VARCHAR( 4000 ), includes

    VARCHAR( 4000 )GO

    DECLARE @isql_key VARCHAR( 4000 ), @isql_incl VARCHAR( 4000 ),@tableid INT , @indexid INT

    DECLARE index_cursor CURSOR FORSELECT tableid , indexidFROM #tmp_indexes

    OPEN index_cursorFETCH NEXT FROM index_cursor INTO @tableid , @indexid

    WHILE @@FETCH_STATUS - 1BEGINSELECT @isql_key = '' , @isql_incl = ''SELECT --ixz.name, colz.colid, colz.name, ixcolz.index_id,ixcolz.object_id, *--key column@isql_key = CASE ixcolz . is_included_columnWHEN 0THEN CASE ixcolz . is_descending_key

    WHEN 1THEN @isql_key + COALESCE( colz . name , '' ) + ' DESC, 'ELSE @isql_key + COALESCE( colz . name , '' ) + ' ASC, 'ENDELSE @isql_keyEND,

    --include column@isql_incl = CASE ixcolz . is_included_columnWHEN 1

  • 8/10/2019 Best SQL Practices on Performance

    23/25

  • 8/10/2019 Best SQL Practices on Performance

    24/25

    Performance Tuning & Maintenance Document Page 24 of 25

    'CREATE ' + CASE WHEN ti . ISUNIQUE = 1 THEN 'UNIQUE ' ELSE '' END + CASE WHEN ti . ISCLUSTERED = 1 THEN 'CLUSTERED ' ELSE '' END + 'INDEX ' + QUOTENAME( ti . INDEXNAME) + ' ON ' + ( ti . TABLENAME) + ' '+ '(' + ti . keycolumns + ')' + CASE WHEN ti . INDEXFILLFACTOR = 0 AND ti . ISCLUSTERED = 1 AND INCLUDES = '' THEN ti . Filter_Definition + ' WITH (SORT_IN_TEMPDB = ON) ON [' + fg . name + ']'WHEN INDEXFILLFACTOR = 0 AND ti . ISCLUSTERED = 0 AND ti . INCLUDES = '' THEN ti . Filter_Definition + ' WITH (ONLINE = ON, SORT_IN_TEMPDB = ON) ON [' + fg . name + ']' WHEN INDEXFILLFACTOR 0 AND ti . ISCLUSTERED = 0 AND ti . INCLUDES = '' THEN ti . Filter_Definition + ' WITH (ONLINE = ON, SORT_IN_TEMPDB = ON,FILLFACTOR = ' + CONVERT( VARCHAR( 10 ), ti . INDEXFILLFACTOR ) + ') ON [' + fg . name + ']'WHEN INDEXFILLFACTOR = 0 AND ti . ISCLUSTERED = 0 AND ti . INCLUDES '' THEN ' INCLUDE (' + ti . INCLUDES + ') ' + ti . Filter_Definition + ' WITH(ONLINE = ON, SORT_IN_TEMPDB = ON) ON [' + fg . name + ']'

    ELSE ' INCLUDE(' + ti . INCLUDES + ') ' + ti . Filter_Definition + ' WITH(FILLFACTOR = ' + CONVERT( VARCHAR( 10 ), ti . INDEXFILLFACTOR ) + ', ONLINE =ON, SORT_IN_TEMPDB = ON) ON [' + fg . name + ']' ENDFROM #tmp_indexes tiJOIN sys . indexes i ON ti . Object_id = i . object_id and ti . indexname = i . nameJOIN sys . filegroups fg on i . data_space_id = fg . data_space_idWHERE LEFT( ti . tablename , 3 ) NOT IN ( 'sys' , 'dt_' ) --exclude system tablesORDER BY ti . tablename , ti . indexid , ti . indexname

    --makes the dropSELECT 'DROP INDEX ' + ' ' + ( tablename ) + '.'+ ( indexname ) + ''FROM #tmp_indexesWHERE LEFT( tablename , 4 ) NOT IN ( '[sys' , 'dt_' )

    ----Drop the temp table againDROP TABLE #tmp_indexes

    3.15 To get the aggregate performance statistics from Plan Cache

    SELECT total_logical_reads , total_logical_writes ,total_physical_reads , total_worker_time , total_elapsed_time , sys . dm_exec_sql_text . TEXTFROM sys . dm_exec_query_stats

  • 8/10/2019 Best SQL Practices on Performance

    25/25

    f f

    CROSS APPLY sys . dm_exec_sql_text ( plan_handle ) WHERE total_logical_reads 0AND total_logical_writes 0ORDER BY ( total_logical_reads + total_logical_writes ) DESC