Famerenana ny fitaovana maimaim-poana SQLIndexManager

Araka ny fantatrao, ny index dia manana anjara toerana lehibe ao amin'ny DBMS, manome fikarohana haingana amin'ireo rakitra ilaina. Izany no antony maha-zava-dehibe ny fanompoana azy ireo ara-potoana. Betsaka ny zavatra nosoratana momba ny fanadihadiana sy ny fanatsarana, anisan'izany ny Internet. Ohatra, ity lohahevitra ity dia nodinihina vao haingana tao Ity publication ity.

Betsaka ny vahaolana karamaina sy maimaim-poana amin'izany. Ohatra, misy efa vita fanapahan-kevitra, mifototra amin'ny fomba fanatsarana ny fanondroana adaptive.

Manaraka, andeha hojerentsika ny fitaovana maimaim-poana SQLIndexManager, nosoratan'i AlanDenton.

Ny fahasamihafana ara-teknika lehibe eo amin'ny SQLIndexManager sy ny analogues hafa dia omen'ny mpanoratra ny tenany eto ΠΈ eto.

Ato amin'ity lahatsoratra ity, hijery ivelany ny tetikasa sy ny fahaiza-miasa amin'ity vahaolana rindrambaiko ity.

Miady hevitra momba ity utility ity eto.
Rehefa nandeha ny fotoana, dia nahitsy ny ankamaroan'ny fanehoan-kevitra sy ny bug.

Noho izany, andeha isika hifindra any amin'ny fampiasa SQLIndexManager.

Ny fampiharana dia voasoratra ao amin'ny C# .NET Framework 4.5 ao amin'ny Visual Studio 2017 ary mampiasa DevExpress amin'ny endrika:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

ary toa izao:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Ny fangatahana rehetra dia noforonina amin'ireto rakitra manaraka ireto:

  1. Index
  2. QUERY
  3. QueryEngine
  4. ServerInfo

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Rehefa mifandray amin'ny angon-drakitra ary mandefa fanontaniana amin'ny DBMS, dia sonia toy izao manaraka izao ny fampiharana:

ApplicationName=”SQLIndexManager”

Rehefa manomboka ny fampiharana ianao, dia hisokatra ny fikandrana modal hanampiana fifandraisana:
Famerenana ny fitaovana maimaim-poana SQLIndexManager

Eto, tsy mbola mandeha ny fametrahana lisitra feno amin'ireo tranga MS SQL Server azo idirana amin'ny tambajotra eo an-toerana.

Azonao atao koa ny manampy fifandraisana amin'ny alΓ lan'ny bokotra havia indrindra amin'ny menio lehibe:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Avy eo, havoaka ireto fanontaniana manaraka ireto amin'ny DBMS:

  1. Mahazoa fampahalalana momba ny DBMS
    SELECT ProductLevel  = SERVERPROPERTY('ProductLevel')
         , Edition       = SERVERPROPERTY('Edition')
         , ServerVersion = SERVERPROPERTY('ProductVersion')
         , IsSysAdmin    = CAST(IS_SRVROLEMEMBER('sysadmin') AS BIT)
    

  2. Mahazoa lisitry ny angon-drakitra misy miaraka amin'ny fananany fohifohy
    SELECT DatabaseName = t.[name]
         , d.DataSize
         , DataUsedSize  = CAST(NULL AS BIGINT)
         , d.LogSize
         , LogUsedSize   = CAST(NULL AS BIGINT)
         , RecoveryModel = t.recovery_model_desc
         , LogReuseWait  = t.log_reuse_wait_desc
    FROM sys.databases t WITH(NOLOCK)
    LEFT JOIN (
        SELECT [database_id]
             , DataSize = SUM(CASE WHEN [type] = 0 THEN CAST(size AS BIGINT) END)
             , LogSize  = SUM(CASE WHEN [type] = 1 THEN CAST(size AS BIGINT) END)
        FROM sys.master_files WITH(NOLOCK)
        GROUP BY [database_id]
    ) d ON d.[database_id] = t.[database_id]
    WHERE t.[state] = 0
        AND t.[database_id] != 2
        AND ISNULL(HAS_DBACCESS(t.[name]), 1) = 1
    

Aorian'ny fanatanterahana ireo sora-baventy etsy ambony dia hiseho ny varavarankely misy fampahalalana fohy momba ny angon-drakitra momba ny ohatra voafantina an'ny MS SQL Server:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Tsara ny manamarika fa ny fampahalalana miitatra dia aseho amin'ny alΓ lan'ny zo. Raha misy sysadmin, dia afaka misafidy angona avy amin'ny fijery ianao sys.master_files. Raha tsy misy zo toy izany, dia kely kokoa ny angona averina fotsiny mba tsy hampiadana ny fangatahana.

Eto ianao dia mila misafidy ny angon-drakitra mahaliana ary tsindrio ny bokotra "OK".

Manaraka, ity script manaraka ity dia hotanterahina ho an'ny angon-drakitra voafantina tsirairay mba hamakafaka ny toetry ny index:

Fandinihana ny satan'ny fanondro

declare @Fragmentation float=15;
declare @MinIndexSize bigint=768;
declare @MaxIndexSize bigint=1048576;
declare @PreDescribeSize bigint=32768;
SET NOCOUNT ON
SET ARITHABORT ON
SET NUMERIC_ROUNDABORT OFF
IF OBJECT_ID('tempdb.dbo.#AllocationUnits') IS NOT NULL
DROP TABLE #AllocationUnits
CREATE TABLE #AllocationUnits (
ContainerID   BIGINT PRIMARY KEY
, ReservedPages BIGINT NOT NULL
, UsedPages     BIGINT NOT NULL
)
INSERT INTO #AllocationUnits (ContainerID, ReservedPages, UsedPages)
SELECT [container_id]
, SUM([total_pages])
, SUM([used_pages])
FROM sys.allocation_units WITH(NOLOCK)
GROUP BY [container_id]
HAVING SUM([total_pages]) BETWEEN @MinIndexSize AND @MaxIndexSize
IF OBJECT_ID('tempdb.dbo.#ExcludeList') IS NOT NULL
DROP TABLE #ExcludeList
CREATE TABLE #ExcludeList (ID INT PRIMARY KEY)
INSERT INTO #ExcludeList
SELECT [object_id]
FROM sys.objects WITH(NOLOCK)
WHERE [type] IN ('V', 'U')
AND ( [is_ms_shipped] = 1 )
IF OBJECT_ID('tempdb.dbo.#Partitions') IS NOT NULL
DROP TABLE #Partitions
SELECT [object_id]
, [index_id]
, [partition_id]
, [partition_number]
, [rows]
, [data_compression]
INTO #Partitions
FROM sys.partitions WITH(NOLOCK)
WHERE [object_id] > 255
AND [rows] > 0
AND [object_id] NOT IN (SELECT * FROM #ExcludeList)
IF OBJECT_ID('tempdb.dbo.#Indexes') IS NOT NULL
DROP TABLE #Indexes
CREATE TABLE #Indexes (
ObjectID         INT NOT NULL
, IndexID          INT NOT NULL
, IndexName        SYSNAME NULL
, PagesCount       BIGINT NOT NULL
, UnusedPagesCount BIGINT NOT NULL
, PartitionNumber  INT NOT NULL
, RowsCount        BIGINT NOT NULL
, IndexType        TINYINT NOT NULL
, IsAllowPageLocks BIT NOT NULL
, DataSpaceID      INT NOT NULL
, DataCompression  TINYINT NOT NULL
, IsUnique         BIT NOT NULL
, IsPK             BIT NOT NULL
, FillFactorValue  INT NOT NULL
, IsFiltered       BIT NOT NULL
, PRIMARY KEY (ObjectID, IndexID, PartitionNumber)
)
INSERT INTO #Indexes
SELECT ObjectID         = i.[object_id]
, IndexID          = i.index_id
, IndexName        = i.[name]
, PagesCount       = a.ReservedPages
, UnusedPagesCount = CASE WHEN ABS(a.ReservedPages - a.UsedPages) > 32 THEN a.ReservedPages - a.UsedPages ELSE 0 END
, PartitionNumber  = p.[partition_number]
, RowsCount        = ISNULL(p.[rows], 0)
, IndexType        = i.[type]
, IsAllowPageLocks = i.[allow_page_locks]
, DataSpaceID      = i.[data_space_id]
, DataCompression  = p.[data_compression]
, IsUnique         = i.[is_unique]
, IsPK             = i.[is_primary_key]
, FillFactorValue  = i.[fill_factor]
, IsFiltered       = i.[has_filter]
FROM #AllocationUnits a
JOIN #Partitions p ON a.ContainerID = p.[partition_id]
JOIN sys.indexes i WITH(NOLOCK) ON i.[object_id] = p.[object_id] AND p.[index_id] = i.[index_id] 
WHERE i.[type] IN (0, 1, 2, 5, 6)
AND i.[object_id] > 255
DECLARE @files TABLE (ID INT PRIMARY KEY)
INSERT INTO @files
SELECT DISTINCT [data_space_id]
FROM sys.database_files WITH(NOLOCK)
WHERE [state] != 0
AND [type] = 0
IF @@ROWCOUNT > 0 BEGIN
DELETE FROM i
FROM #Indexes i
LEFT JOIN sys.destination_data_spaces dds WITH(NOLOCK) ON i.DataSpaceID = dds.[partition_scheme_id] AND i.PartitionNumber = dds.[destination_id]
WHERE ISNULL(dds.[data_space_id], i.DataSpaceID) IN (SELECT * FROM @files)
END
DECLARE @DBID   INT
, @DBNAME SYSNAME
SET @DBNAME = DB_NAME()
SELECT @DBID = [database_id]
FROM sys.databases WITH(NOLOCK)
WHERE [name] = @DBNAME
IF OBJECT_ID('tempdb.dbo.#Fragmentation') IS NOT NULL
DROP TABLE #Fragmentation
CREATE TABLE #Fragmentation (
ObjectID         INT NOT NULL
, IndexID          INT NOT NULL
, PartitionNumber  INT NOT NULL
, Fragmentation    FLOAT NOT NULL
, PRIMARY KEY (ObjectID, IndexID, PartitionNumber)
)
INSERT INTO #Fragmentation (ObjectID, IndexID, PartitionNumber, Fragmentation)
SELECT i.ObjectID
, i.IndexID
, i.PartitionNumber
, r.[avg_fragmentation_in_percent]
FROM #Indexes i
CROSS APPLY sys.dm_db_index_physical_stats(@DBID, i.ObjectID, i.IndexID, i.PartitionNumber, 'LIMITED') r
WHERE i.PagesCount <= @PreDescribeSize
AND r.[index_level] = 0
AND r.[alloc_unit_type_desc] = 'IN_ROW_DATA'
AND i.IndexType IN (0, 1, 2)
IF OBJECT_ID('tempdb.dbo.#Columns') IS NOT NULL
DROP TABLE #Columns
CREATE TABLE #Columns (
ObjectID     INT NOT NULL
, ColumnID     INT NOT NULL
, ColumnName   SYSNAME NULL
, SystemTypeID TINYINT NULL
, IsSparse     BIT
, IsColumnSet  BIT
, MaxLen       INT
, PRIMARY KEY (ObjectID, ColumnID)
)
INSERT INTO #Columns
SELECT ObjectID     = [object_id]
, ColumnID     = [column_id]
, ColumnName   = [name]
, SystemTypeID = [system_type_id]
, IsSparse     = [is_sparse]
, IsColumnSet  = [is_column_set]
, MaxLen       = [max_length]
FROM sys.columns WITH(NOLOCK)
WHERE [object_id] IN (SELECT DISTINCT i.ObjectID FROM #Indexes i)
IF OBJECT_ID('tempdb.dbo.#IndexColumns') IS NOT NULL
DROP TABLE #IndexColumns
CREATE TABLE #IndexColumns (
ObjectID   INT NOT NULL
, IndexID    INT NOT NULL
, OrderID    INT NOT NULL
, ColumnID   INT NOT NULL
, IsIncluded BIT NOT NULL
, PRIMARY KEY (ObjectID, IndexID, ColumnID)
)
INSERT INTO #IndexColumns
SELECT ObjectID   = [object_id]
, IndexID    = [index_id]
, OrderID    = CASE WHEN [is_included_column] = 0 THEN [key_ordinal] ELSE [index_column_id] END
, ColumnID   = [column_id]
, IsIncluded = ISNULL([is_included_column], 0)
FROM sys.index_columns ic WITH(NOLOCK)
WHERE EXISTS(
SELECT *
FROM #Indexes i
WHERE i.ObjectID = ic.[object_id]
AND i.IndexID = ic.[index_id]
AND i.IndexType IN (1, 2)
)
IF OBJECT_ID('tempdb.dbo.#Lob') IS NOT NULL
DROP TABLE #Lob
CREATE TABLE #Lob (
ObjectID    INT NOT NULL
, IndexID     INT NOT NULL
, IsLobLegacy BIT
, IsLob       BIT
, PRIMARY KEY (ObjectID, IndexID)
)
INSERT INTO #Lob (ObjectID, IndexID, IsLobLegacy, IsLob)
SELECT c.ObjectID
, IndexID     = ISNULL(i.IndexID, 1)
, IsLobLegacy = MAX(CASE WHEN c.SystemTypeID IN (34, 35, 99) THEN 1 END)
, IsLob       = 0
FROM #Columns c
LEFT JOIN #IndexColumns i ON c.ObjectID = i.ObjectID AND c.ColumnID = i.ColumnID
WHERE c.SystemTypeID IN (34, 35, 99)
GROUP BY c.ObjectID
, i.IndexID
IF OBJECT_ID('tempdb.dbo.#Sparse') IS NOT NULL
DROP TABLE #Sparse
CREATE TABLE #Sparse (ObjectID INT PRIMARY KEY)
INSERT INTO #Sparse
SELECT DISTINCT ObjectID
FROM #Columns
WHERE IsSparse = 1
OR IsColumnSet = 1
IF OBJECT_ID('tempdb.dbo.#AggColumns') IS NOT NULL
DROP TABLE #AggColumns
CREATE TABLE #AggColumns (
ObjectID        INT NOT NULL
, IndexID         INT NOT NULL
, IndexColumns    NVARCHAR(MAX)
, IncludedColumns NVARCHAR(MAX)
, PRIMARY KEY (ObjectID, IndexID)
)
INSERT INTO #AggColumns
SELECT t.ObjectID
, t.IndexID
, IndexColumns = STUFF((
SELECT ', [' + c.ColumnName + ']'
FROM #IndexColumns i
JOIN #Columns c ON i.ObjectID = c.ObjectID AND i.ColumnID = c.ColumnID
WHERE i.ObjectID = t.ObjectID
AND i.IndexID = t.IndexID
AND i.IsIncluded = 0
ORDER BY i.OrderID
FOR XML PATH(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 2, '')
, IncludedColumns = STUFF((
SELECT ', [' + c.ColumnName + ']'
FROM #IndexColumns i
JOIN #Columns c ON i.ObjectID = c.ObjectID AND i.ColumnID = c.ColumnID
WHERE i.ObjectID = t.ObjectID
AND i.IndexID = t.IndexID
AND i.IsIncluded = 1
ORDER BY i.OrderID
FOR XML PATH(''), TYPE).value('(./text())[1]', 'NVARCHAR(MAX)'), 1, 2, '')
FROM (
SELECT DISTINCT ObjectID, IndexID
FROM #Indexes
WHERE IndexType IN (1, 2)
) t
SELECT i.ObjectID
, i.IndexID
, i.IndexName
, ObjectName       = o.[name]
, SchemaName       = s.[name]
, i.PagesCount
, i.UnusedPagesCount
, i.PartitionNumber
, i.RowsCount
, i.IndexType
, i.IsAllowPageLocks
, u.TotalWrites
, u.TotalReads
, u.TotalSeeks
, u.TotalScans
, u.TotalLookups
, u.LastUsage
, i.DataCompression
, f.Fragmentation
, IndexStats       = STATS_DATE(i.ObjectID, i.IndexID)
, IsLobLegacy      = ISNULL(lob.IsLobLegacy, 0)
, IsLob            = ISNULL(lob.IsLob, 0)
, IsSparse         = CAST(CASE WHEN p.ObjectID IS NULL THEN 0 ELSE 1 END AS BIT)
, IsPartitioned    = CAST(CASE WHEN dds.[data_space_id] IS NOT NULL THEN 1 ELSE 0 END AS BIT)
, FileGroupName    = fg.[name]
, i.IsUnique
, i.IsPK
, i.FillFactorValue
, i.IsFiltered
, a.IndexColumns
, a.IncludedColumns
FROM #Indexes i
JOIN sys.objects o WITH(NOLOCK) ON o.[object_id] = i.ObjectID
JOIN sys.schemas s WITH(NOLOCK) ON s.[schema_id] = o.[schema_id]
LEFT JOIN #AggColumns a ON a.ObjectID = i.ObjectID AND a.IndexID = i.IndexID
LEFT JOIN #Sparse p ON p.ObjectID = i.ObjectID
LEFT JOIN #Fragmentation f ON f.ObjectID = i.ObjectID AND f.IndexID = i.IndexID AND f.PartitionNumber = i.PartitionNumber
LEFT JOIN (
SELECT ObjectID      = [object_id]
, IndexID       = [index_id]
, TotalWrites   = NULLIF([user_updates], 0)
, TotalReads    = NULLIF([user_seeks] + [user_scans] + [user_lookups], 0)
, TotalSeeks    = NULLIF([user_seeks], 0)
, TotalScans    = NULLIF([user_scans], 0)
, TotalLookups  = NULLIF([user_lookups], 0)
, LastUsage     = (
SELECT MAX(dt)
FROM (
VALUES ([last_user_seek])
, ([last_user_scan])
, ([last_user_lookup])
, ([last_user_update])
) t(dt)
)
FROM sys.dm_db_index_usage_stats WITH(NOLOCK)
WHERE [database_id] = @DBID
) u ON i.ObjectID = u.ObjectID AND i.IndexID = u.IndexID
LEFT JOIN #Lob lob ON lob.ObjectID = i.ObjectID AND lob.IndexID = i.IndexID
LEFT JOIN sys.destination_data_spaces dds WITH(NOLOCK) ON i.DataSpaceID = dds.[partition_scheme_id] AND i.PartitionNumber = dds.[destination_id]
JOIN sys.filegroups fg WITH(NOLOCK) ON ISNULL(dds.[data_space_id], i.DataSpaceID) = fg.[data_space_id] 
WHERE o.[type] IN ('V', 'U')
AND (
f.Fragmentation >= @Fragmentation
OR
i.PagesCount > @PreDescribeSize
OR
i.IndexType IN (5, 6)
)

Araka ny hita avy amin'ny fanontaniana, ny latabatra vonjimaika dia ampiasaina matetika. Izany dia atao mba tsy hisian'ny recompilations, ary raha misy drafitra lehibe, ny drafitra dia azo amboarina amin'ny parallèle rehefa mampiditra angon-drakitra, satria ny fampidirana ny variables latabatra dia azo atao amin'ny kofehy iray ihany.

Aorian'ny fanatanterahana ny script etsy ambony dia hiseho ny varavarankely misy tabilao index:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Azonao atao koa ny mampiseho fampahalalana amin'ny antsipiriany hafa eto, toy ny:

  1. banky angona
  2. isan'ny fizarana
  3. daty sy ora niantsoana farany
  4. famatrarana
  5. filegroup

i t. d.
Ny mpandahateny dia azo atao manokana:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Ao amin'ny sela ao amin'ny tsanganana Fix, azonao atao ny misafidy izay hetsika hatao mandritra ny fanatsarana. Ary koa, rehefa vita ny scan, dia misy hetsika default voafantina mifototra amin'ny toe-javatra voafantina:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Tsy maintsy misafidy ny fanondroana tianao hokarakaraina ianao.

Amin'ny fampiasana ny menio lehibe, azonao atao ny mitahiry ny script (io bokotra io ihany no manomboka ny fizotran'ny fanatsarana ny index):

Famerenana ny fitaovana maimaim-poana SQLIndexManager

ary tehirizo ny latabatra amin'ny endrika samihafa (ny bokotra iray ihany dia ahafahanao manokatra fika amin'ny antsipiriany ho an'ny famakafakana sy fanatsarana ny indeks):

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Azonao atao koa ny manavao ny vaovao amin'ny fipihana ny bokotra fahatelo eo ankavia amin'ny sakafo lehibe eo akaikin'ny fitaratra lehibe.

Ny bokotra misy vera fanamafisam-peo dia ahafahanao misafidy ny angon-drakitra tiana hodinihina.

Tsy misy rafitra fanampiana feno amin'izao fotoana izao. Noho izany, tsindrio ny bokotra "?" dia hahatonga fikandrana modaly hiseho fotsiny misy fampahalalana fototra momba ny vokatra rindrambaiko:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Ho fanampin'ny zavatra rehetra voalaza etsy ambony, misy bara fitadiavana ny sakafo fototra:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Rehefa manomboka ny fizotran'ny optimization index:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Azonao atao ihany koa ny mijery ny diarin'ny hetsika natao eo amin'ny faran'ny varavarankely:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Ao amin'ny varavarankelin'ny toe-javatra amin'ny antsipiriany ho an'ny famakafakana sy ny fanatsarana ny index, dia azonao atao ny manitsy safidy an-kolaka kokoa:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

Fangatahana fangatahana:

  1. ataovy azo atao ny manavao ny antontan'isa tsy ho an'ny index ihany fa amin'ny fomba samihafa (fanavaozana tanteraka na ampahany)
  2. ataovy azo atao tsy ny mifidy angon-drakitra fotsiny, fa koa ireo mpizara samihafa (tena mety izany rehefa misy tranga maro amin'ny MS SQL Server)
  3. Ho an'ny flexibility bebe kokoa amin'ny fampiasana, dia soso-kevitra ny hamehezana ny baiko ao amin'ny tranomboky ary hamoaka azy ireo amin'ny baiko PowerShell, toy ny atao, ohatra, eto:
  4. dbatools.io/commands
  5. Ataovy azo atao ny mitahiry sy manova ny toe-javatra manokana ho an'ny fampiharana manontolo ary, raha ilaina, ho an'ny MS SQL Server tsirairay sy ny tahiry tsirairay.
  6. Avy amin'ny teboka 2 sy 4, dia manaraka izany fa te hamorona vondrona amin'ny angon-drakitra sy vondrona amin'ny MS SQL Server ohatra ianao, izay mitovy ny toe-javatra.
  7. karohy fanondroana dika mitovy (feno sy tsy feno, izay samy hafa kely na tsy mitovy afa-tsy amin'ireo tsanganana tafiditra)
  8. Satria ny SQLIndexManager dia tsy ampiasaina afa-tsy amin'ny MS SQL Server DBMS, dia ilaina ny maneho izany amin'ny anarana, ohatra, toy izao manaraka izao: SQLIndexManager ho an'ny MS SQL Server
  9. Alefaso any amin'ny maody misaraka avokoa ny ampahany tsy GUI amin'ny fampiharana ary soraty ao amin'ny .NET Core 2.1.

Amin'ny fotoana anoratana, ny laharana faha-6 amin'ireo faniriana dia eo am-pamolavolana mavitrika ary efa misy ny fanohanana amin'ny endrika fitadiavana ireo dika mitovy feno sy mitovy:

Famerenana ny fitaovana maimaim-poana SQLIndexManager

loharanom-baovao

Source: www.habr.com

Add a comment