SQL performance is key to releasing Enterprise Vault (EV) threads and to conserve resources. Many EV threads request an action by SQL in order to complete their task. Once the task is complete, the thread becomes idle and is marked to be deleted during a garbage run. The garbage run deletes these threads and places the memory used by the idle threads back into the application memory pool to be used by other worker threads.
Stale SQL Statistics and excessive Logical and Extent fragmentation of SQL indexes, play a huge role in SQL stored procedure performance. Threads will ‘stack up’ to wait for access to the SQL tables/views. The longer the wait, the more threads will stack up with more memory being consumed by the worker threads. So it is critical for programs that rely tremendously on SQL, like EV and the Accelerator products, to have the Statistics and Index fragmentation monitored and maintained. Maintenance must be performed in order for SQL to run efficiently.
INDICES:
1. Starting with the line: Table: 'tblIntDiscoveredItems' (1364915934); index ID: 1, database ID: 5.
2. Pages Scanned – rule of thumb is to ignore tables with less than 1,000 pages. SQL processes will run through tables with less than a thousand pages quickly enough to not cause any noticeable latency.
3. Logical Scan Fragmentation – item order within an extent (explained next). When Logical Scan Fragmentation reaches above 10%, latency will begin to be apparent and once Logical Scan Fragmentation reaches above 50% , the index usage is significantly slower when executing stored procedures that make use of the index.
4. Extent Scan Fragmentation – page order fragmentation. An extent is 8 pages of index. An extent is loaded into memory when an index is called. If the pages are out of order to an extent of over 70% fragmentation, noticeable latency will occur.
5. Avg. Page Density (full) – is the percentage of data that fills each index page. If the percentage is below 50%, each Extent read into memory will be equivalent to less than 4 pages of index data instead of the optimal 8 pages. Once maintenance is performed to alleviate index fragmentation, the average page density will increase to above 90%.
1. Index ID = 1, so it qualifies to be examined.
2. Pages Scanned is above 1,000 pages making the index fragmentation important.
3. Logical Scan Fragmentation is not only above 10% which causes noticeable latency, but is above 50% which makes the index usage significantly slower.
4. Extent Scan fragmentation is above 70% also causing extensive latency.
5. Average Page Density is way below 90% causing more index reads to navigate through an index.
1. Table access (reads) will force SQL maintenance to only deal with the fragmentation of the items in memory, or an extent. So, when services are running that access the tables in a database, SQL will not be able to swap pages between extents and thus only be able to defragment the logical order of index items and not the extent or page order. This will become evident as time progresses and logical Scan Fragmentation is low, but Extent Scan Fragmentation continues to climb; this is why Veritas recommends stopping all services prior to performing SQL maintenance.
2. Once Logical Scan Fragmentation reaches 100% , standard SQL maintenance will not be able to properly defragment the indexed items. A manual script can be run in order to defragment those indices.
A. Stop the EV and Accelerator services for those databases.
B. Run the following script against the appropriate database.
-- Ensure a USE statement has been executed first.
USE DB_NAME
SET NOCOUNT ON;
DECLARE @objectid int;
DECLARE @indexid int;
DECLARE @partitioncount bigint;
DECLARE @schemaname nvarchar(130);
DECLARE @objectname nvarchar(130);
DECLARE @indexname nvarchar(130);
DECLARE @partitionnum bigint;
DECLARE @partitions bigint;
DECLARE @frag float;
DECLARE @command nvarchar(4000);
-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT
object_id AS objectid,
index_id AS indexid,
partition_number AS partitionnum,
avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 5.0 AND index_id > 0;
-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR FOR
SELECT * FROM #work_to_do;
-- Open the cursor.
OPEN partitions;
-- Loop through the partitions.
WHILE (1=1)
BEGIN;
FETCH NEXT
FROM partitions
INTO @objectid, @indexid, @partitionnum, @frag;
IF @@FETCH_STATUS < 0 BREAK;
SELECT @objectname = QUOTENAME(o.name), @schemaname = QUOTENAME(s.name)
FROM sys.objects AS o
JOIN sys.schemas as s ON s.schema_id = o.schema_id
WHERE o.object_id = @objectid;
SELECT @indexname = QUOTENAME(name)
FROM sys.indexes
WHERE object_id = @objectid AND index_id = @indexid;
SELECT @partitioncount = count (*)
FROM sys.partitions
WHERE object_id = @objectid AND index_id = @indexid;
-- 10 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
IF @frag < 10.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';
IF @frag >= 10.0
SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';
IF @partitioncount > 1
SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS nvarchar(10));
EXEC (@command);
PRINT N'Executed: ' + @command;
END;
-- Close and deallocate the cursor.
CLOSE partitions;
DEALLOCATE partitions;
-- Drop the temporary table.
DROP TABLE #work_to_do;
GO
Note: The script above was originally published by Microsoft. However, the fragmentation percent was modified from 30% to 10% for a more aggressive defragmentation process.
USE DB_Name
SELECT o.name 'Table Name', i.name 'Index Name', i.type 'Index Type'
,STATS_DATE(i.[object_id], i.[index_id]) 'Last Statistics Update'
FROM sys.indexes i, sys.objects o
WHERE i.[object_id]=o.[object_id]
AND o.type='U' AND i.name IS NOT NULL
AND STATS_DATE(i.object_id, i.index_id) < DATEADD(DAY, -1, GETDATE())
ORDER BY 'Last Statistics Update' DESC