ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ื•ื•ื™ ืื™ืจ ื•ื•ื™ืกืŸ, ื™ื ื“ืขืงืกื™ื– ืฉืคึผื™ืœืŸ ืึท ื•ื•ื™ื›ื˜ื™ืง ืจืึธืœืข ืื™ืŸ ืึท DBMS, ืคึผืจืึทื•ื•ื™ื™ื“ื™ื ื’ ืึท ืฉื ืขืœ ื–ื•ื›ืŸ ืฆื• ื“ื™ ืคืืจืœืื ื’ื˜ ืจืขืงืึธืจื“ืก. ืึทื– ืก ื•ื•ืึธืก ืขืก ืื™ื– ืึทื–ื•ื™ ื•ื•ื™ื›ื˜ื™ืง ืฆื• ื“ื™ื ืขืŸ ื–ื™ื™ ืื™ืŸ ืึท ื‘ื™ื™ึทืฆื™ื™ึทื˜ื™ืง ืฉื˜ื™ื™ื’ืขืจ. ื’ืึทื ืฅ ืึท ืคึผืœืึทืฅ ืคื•ืŸ ืžืึทื˜ืขืจื™ืึทืœ ืื™ื– ื’ืขืฉืจื™ื‘ืŸ ื•ื•ืขื’ืŸ ืึทื ืึทืœื™ืกื™ืก ืื•ืŸ ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ, ืึทืจื™ื™ึทื ื’ืขืจืขื›ื ื˜ ืื•ื™ืฃ ื“ืขืจ ืื™ื ื˜ืขืจื ืขืฅ. ืคึฟืึทืจ ื‘ื™ื™ึทืฉืคึผื™ืœ, ื“ืขื ื˜ืขืžืข ืื™ื– ืœืขืฆื˜ื ืก ืจื™ื•ื•ื™ื•ื“ ืื™ืŸ ื“ืขื ื•ื™ืกื’ืึทื‘ืข.

ืขืก ื–ืขื ืขืŸ ืคื™ืœืข ื‘ืึทืฆืึธืœื˜ ืื•ืŸ ืคืจื™ื™ ืกืึทืœื•ืฉืึทื ื– ืคึฟืึทืจ ื“ืขื. ืคึฟืึทืจ ื‘ื™ื™ึทืฉืคึผื™ืœ, ืขืก ืื™ื– ืึท ืคืึทืจื˜ื™ืง ื‘ืึทืฉืœื•ืก, ื‘ืื–ื™ืจื˜ ืื•ื™ืฃ ืึท ืึทื“ืึทืคึผื˜ื™ื•ื• ืื™ื ื“ืขืงืก ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ ืื•ืคึฟืŸ.

ื•ื•ื™ื™ึทื˜ืขืจ, ืœืึธืžื™ืจ ื–ืขืŸ ื“ื™ ืคืจื™ื™ ื ื•ืฆืŸ SQLIndexManager, ื’ืขืฉืจื™ื‘ืŸ ื“ื•ืจืš ืึทืœืึทื ื“ืขื ื˜ืึธืŸ.

ื“ืขืจ ื”ื•ื™ืคึผื˜ ื˜ืขื›ื ื™ืฉ ื—ื™ืœื•ืง ืฆื•ื•ื™ืฉืŸ SQLIndexManager ืื•ืŸ ืึท ื ื•ืžืขืจ ืคื•ืŸ ืื ื“ืขืจืข ืึทื ืึทืœืึธื’ื•ืขืก ืื™ื– ื’ืขื’ืขื‘ืŸ ื“ื•ืจืš ื“ืขืจ ืžื—ื‘ืจ ื–ื™ืš ื“ืึธ ะธ ื“ืึธ.

ืื™ืŸ ื“ืขื ืึทืจื˜ื™ืงืœ, ืžื™ืจ ื•ื•ืขืœืŸ ืงื•ืงืŸ ืื™ืŸ ื“ื™ ืคึผืจื•ื™ืขืงื˜ ืื•ืŸ ื“ื™ ืึทืคึผืขืจื™ื™ืฉืึทื ืึทืœ ืงื™ื™ืคึผืึทื‘ื™ืœืึทื˜ื™ื– ืคื•ืŸ ื“ืขื ื•ื•ื™ื™ื›ื•ื•ืืจื’ ืœื™ื™ื–ื•ื ื’.

ื“ื™ืกืงื•ื˜ื™ืจืŸ ื“ืขื ื ื•ืฆืŸ ื“ืึธ.
ืžื™ื˜ ื“ืขืจ ืฆื™ื™ื˜, ืจื•ื‘ึฟ ืคื•ืŸ ื“ื™ ื‘ืึทืžืขืจืงื•ื ื’ืขืŸ ืื•ืŸ ื‘ืึทื’ื– ื–ืขื ืขืŸ ืงืขืจืขืงื˜ืึทื“.

ืœืึธืžื™ืจ ืื™ืฆื˜ ื’ื™ื™ืŸ ืฆื• ื“ื™ SQLIndexManager ื ื•ืฆืŸ ื–ื™ืš.

ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืื™ื– ื’ืขืฉืจื™ื‘ืŸ ืื™ืŸ C # .NET Framework 4.5 ืื™ืŸ ื•ื•ื™ืกื•ืึทืœ ืกื˜ื•ื“ื™ืึธ 2017 ืื•ืŸ ื ื™ืฆื˜ DevExpress ืคึฟืึทืจ ืคืืจืžืขืŸ:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื•ืŸ ืงื•ืงื˜ ื•ื•ื™ ื“ืึธืก:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืึทืœืข ืจื™ืงื•ื•ืขืก ื–ืขื ืขืŸ ื“ื–ืฉืขื ืขืจื™ื™ื˜ืึทื“ ืื™ืŸ ื“ื™ ืคืืœื’ืขื ื“ืข ื˜ืขืงืขืก:

  1. ื™ื ื“ืขืงืก
  2. ืึธื ืคึฟืจืขื’
  3. QueryEngine
  4. ืกืขืจื•ื•ื™ืจืขืจ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ื•ื•ืขืŸ ืงืึทื ืขืงื˜ื™ื ื’ ืฆื• ืึท ื“ืึทื˜ืึทื‘ื™ื™ืก ืื•ืŸ ืฉื™ืงืŸ ืคึฟืจืื’ืŸ ืฆื• ื“ื™ DBMS, ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืื™ื– ื’ืขื—ืชืžืขื˜ ื•ื•ื™ ื’ื™ื™ื˜:

ApplicationName=โ€SQLIndexManagerโ€

ื•ื•ืขืŸ ืื™ืจ ืงืึทื˜ืขืจ ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ, ืึท ืžืึธื“ืึทืœ ืคึฟืขื ืฆื˜ืขืจ ื•ื•ืขื˜ ืขืคืขื ืขืŸ ืฆื• ืœื™ื™ื’ืŸ ืึท ืงืฉืจ:
ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ื“ืึธ, ืœืึธื•ื“ื™ื ื’ ืึท ื’ืึทื ืฅ ืจืฉื™ืžื” ืคื•ืŸ ืึทืœืข MS SQL Server ื™ื ืกื˜ืึทื ืกื™ื– ืฆื•ื˜ืจื™ื˜ืœืขืš ืื™ื‘ืขืจ ื”ื™ื’ืข ื ืขื˜ื•ื•ืึธืจืงืก ื˜ื•ื˜ ื ื™ืฉื˜ ื ืึธืš ืึทืจื‘ืขื˜.

ืื™ืจ ืงืขื ื˜ ืื•ื™ืš ืœื™ื™ื’ืŸ ืึท ืคึฟืึทืจื‘ื™ื ื“ื•ื ื’ ืžื™ื˜ ื“ื™ ืœื™ื ืงืก-ืžืึธืกื˜ ืงื ืขืคึผืœ ืื™ืŸ ื“ื™ ื”ื•ื™ืคึผื˜ ืžืขื ื™ื•:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ื“ืขืจื ืึธืš, ื“ื™ ืคืืœื’ืขื ื“ืข ืคึฟืจืื’ืŸ ืฆื• ื“ื™ DBMS ื•ื•ืขื˜ ื–ื™ื™ืŸ ืœืึธื ื˜ืฉื˜:

  1. ื‘ืึทืงื•ืžืขืŸ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื•ื•ืขื’ืŸ ื“ื™ DBMS
    SELECT ProductLevel  = SERVERPROPERTY('ProductLevel')
         , Edition       = SERVERPROPERTY('Edition')
         , ServerVersion = SERVERPROPERTY('ProductVersion')
         , IsSysAdmin    = CAST(IS_SRVROLEMEMBER('sysadmin') AS BIT)
    

  2. ื‘ืึทืงื•ืžืขืŸ ืึท ืจืฉื™ืžื” ืคื•ืŸ ื‘ื ื™ืžืฆื ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืžื™ื˜ ื–ื™ื™ืขืจ ืงื•ืจืฅ ืคึผืจืึธืคึผืขืจื˜ื™ืขืก
    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
    

ื ืึธืš ืขืงืกืึทืงื™ื•ื˜ื™ื ื’ ื“ื™ ืื•ื™ื‘ืŸ ืกืงืจื™ืคึผืก, ืึท ืคึฟืขื ืฆื˜ืขืจ ื•ื•ืขื˜ ื“ืขืจืฉื™ื™ึทื ืขืŸ ืžื™ื˜ ืงื•ืจืฅ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื•ื•ืขื’ืŸ ื“ื™ ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืคื•ืŸ ื“ื™ ืื•ื™ืกื’ืขืงืœื™ื‘ืŸ ื‘ื™ื™ึทืฉืคึผื™ืœ ืคื•ืŸ MS SQL Server:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืขืก ืื™ื– ื›ื“ืื™ ืฆื• ื‘ืืžืขืจืงืŸ ืึทื– ืขืงืกื˜ืขื ื“ืขื“ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ืื™ื– ื’ืขื•ื•ื™ื–ืŸ ื‘ืื–ื™ืจื˜ ืื•ื™ืฃ ืจืขื›ื˜. ืื•ื™ื‘ ืขืก ืกื™ืกืึทื“ืžื™ืŸ, ื“ืขืžืึธืœื˜ ืื™ืจ ืงืขื ืขืŸ ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ื“ืึทื˜ืŸ ืคื•ืŸ ื“ื™ ืžื™ื™ื ื•ื ื’ sys.master_files. ืื•ื™ื‘ ืขืก ื–ืขื ืขืŸ ื ื™ื˜ ืึทื–ืึท ืจืขื›ื˜, ื•ื•ื™ื™ื ื™ืงืขืจ ื“ืึทื˜ืŸ ืื™ื– ืคืฉื•ื˜ ืื•ืžื’ืขืงืขืจื˜ ืึทื–ื•ื™ ื ื™ืฉื˜ ืฆื• ืคึผืึทืžืขืœืขืš ื“ื™ ื‘ืงืฉื”.

ื“ืึธ ืื™ืจ ื“ืึทืจืคึฟืŸ ืฆื• ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ื“ื™ ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืคื•ืŸ ืื™ื ื˜ืขืจืขืก ืื•ืŸ ื’ื™ื˜ ื“ื™ "ื’ื•ื˜" ืงื ืขืคึผืœ.

ื“ืขืจื ืึธืš, ื“ื™ ืคืืœื’ืขื ื“ืข ืฉืจื™ืคื˜ ื•ื•ืขื˜ ื–ื™ื™ืŸ ืขืงืกืึทืงื™ื•ื˜ืึทื“ ืคึฟืึทืจ ื™ืขื“ืขืจ ืื•ื™ืกื’ืขืงืœื™ื‘ืŸ ื“ืึทื˜ืึทื‘ื™ื™ืก ืฆื• ืึทื ืึทืœื™ื™ื– ื“ื™ ืฉื˜ืึทื˜ ืคื•ืŸ ื“ื™ ื™ื ื“ืขืงืกื™ื–:

ืื™ื ื“ืขืงืก ืกื˜ืึทื˜ื•ืก ืึทื ืึทืœื™ืกื™ืก

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)
)

ื•ื•ื™ ืงืขื ืขืŸ ื–ื™ื™ืŸ ื’ืขื–ืขืŸ ืคื•ืŸ ื“ื™ ืคึฟืจืื’ืŸ ื–ื™ืš, ืฆื™ื™ื˜ื•ื•ื™ื™ืœื™ื’ืข ื˜ื™ืฉืŸ ื–ืขื ืขืŸ ื’ืึทื ืฅ ืึธืคื˜ ื’ืขื ื™ืฆื˜. ื“ืึธืก ืื™ื– ื’ืขื˜ืืŸ ืึทื–ื•ื™ ืึทื– ืขืก ื–ืขื ืขืŸ ืงื™ื™ืŸ ืจืขืงืึธืžืคึผื™ืœืึทื˜ื™ืึธื ืก, ืื•ืŸ ืื™ืŸ ื“ืขื ืคืึทืœ ืคื•ืŸ ืึท ื’ืจื•ื™ืก ืกื›ืขืžืข, ื“ื™ ืคึผืœืึทืŸ ืงืขื ืขืŸ ื–ื™ื™ืŸ ื“ื–ืฉืขื ืขืจื™ื™ื˜ืึทื“ ืื™ืŸ ืคึผืึทืจืึทืœืขืœ ื•ื•ืขืŸ ื™ื ืกืขืจื˜ื™ื ื’ ื“ืึทื˜ืŸ, ื•ื•ื™ื™ึทืœ ื™ื ืกืขืจื˜ื™ื ื’ ื˜ื™ืฉ ื•ื•ืขืจื™ืึทื‘ืึทืœื– ืื™ื– ืžืขื’ืœืขืš ื‘ืœื•ื™ื– ืื™ืŸ ืื™ื™ืŸ ืคืึธื“ืขื.

ื ืึธืš ืขืงืกืึทืงื™ื•ื˜ื™ื ื’ ื“ื™ ืื•ื™ื‘ืŸ ืฉืจื™ืคื˜, ืึท ืคึฟืขื ืฆื˜ืขืจ ืžื™ื˜ ืึทืŸ ืื™ื ื“ืขืงืก ื˜ื™ืฉ ื•ื•ืขื˜ ื“ืขืจืฉื™ื™ึทื ืขืŸ:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืจ ืงืขื ื˜ ืื•ื™ืš ื•ื•ื™ื™ึทื–ืŸ ืื ื“ืขืจืข ื“ื™ื˜ื™ื™ืœื“ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื“ืึธ, ืึทื–ืึท ื•ื•ื™:

  1. ื“ืึทื˜ืึทื‘ื™ื™ืก
  2. ื ื•ืžืขืจ ืคื•ืŸ ืกืขืงืฉืึทื ื–
  3. ื“ืึทื˜ืข ืื•ืŸ ืฆื™ื™ื˜ ืคื•ืŸ ืœืขืฆื˜ืข ืจื•ืคืŸ
  4. ืฆื•ื–ืืžืงื•ื•ืขื˜ืฉืŸ
  5. ื˜ืขืงืข ื’ืจื•ืคึผืข

ืื•ืŸ ื”. ื“.
ื“ื™ ืกืคึผื™ืงืขืจื– ื–ื™ืš ืงืขื ืขืŸ ื–ื™ื™ืŸ ืงืึทืกื˜ืึทืžื™ื™ื–ื“:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืŸ ื“ื™ ืกืขืœื– ืคื•ืŸ ื“ื™ Fix ื–ื™ื™ึทืœ, ืื™ืจ ืงืขื ืขืŸ ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ื•ื•ืึธืก ืงืึทืžืฃ ื•ื•ืขื˜ ื–ื™ื™ืŸ ื’ืขื˜ืืŸ ื‘ืขืฉืึทืก ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ. ืื•ื™ืš, ื•ื•ืขืŸ ื“ื™ ื™ื‘ืขืจืงื•ืงืŸ ืงืึทืžืคึผืœื™ืฅ, ืึท ืคืขืœื™ืงื™ื™ึทื˜ ืงืึทืžืฃ ืื™ื– ืื•ื™ืกื’ืขืงืœื™ื‘ืŸ ื‘ืื–ื™ืจื˜ ืื•ื™ืฃ ื“ื™ ืื•ื™ืกื’ืขืงืœื™ื‘ืŸ ืกืขื˜ื˜ื™ื ื’ืก:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืจ ืžื•ื–ืŸ ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ื“ื™ ื’ืขื•ื•ืืœื˜ ื™ื ื“ืขืงืกื™ื– ืคึฟืึทืจ ืคึผืจืึทืกืขืกื™ื ื’.

ื ื™ืฆืŸ ื“ื™ ื”ื•ื™ืคึผื˜ ืžืขื ื™ื•, ืื™ืจ ืงืขื ืขืŸ ืจืึทื˜ืขื•ื•ืขืŸ ื“ื™ ืฉืจื™ืคื˜ (ื“ืขืจ ื–ืขืœื‘ื™ืงืขืจ ืงื ืขืคึผืœ ืกื˜ืึทืจืฅ ื“ื™ ืื™ื ื“ืขืงืก ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ ืคึผืจืึธืฆืขืก ื–ื™ืš):

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื•ืŸ ืจืึทื˜ืขื•ื•ืขืŸ ื“ื™ ื˜ื™ืฉ ืื™ืŸ ืคืึทืจืฉื™ื“ืขื ืข ืคึฟืึธืจืžืึทื˜ื™ืจื•ื ื’ืขืŸ (ื“ืขืจ ื–ืขืœื‘ื™ืงืขืจ ืงื ืขืคึผืœ ืึทืœืึทื•ื– ืื™ืจ ืฆื• ืขืคึฟืขื ืขืŸ ื“ื™ื˜ื™ื™ืœื“ ืกืขื˜ื˜ื™ื ื’ืก ืคึฟืึทืจ ืึทื ืึทืœื™ื™ื–ื™ื ื’ ืื•ืŸ ืึธืคึผื˜ื™ืžื™ื–ื™ื ื’ ื™ื ื“ืขืงืกื™ื–):

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืจ ืงืขื ื˜ ืื•ื™ืš ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงืŸ ื“ื™ ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื“ื•ืจืš ื’ืขื‘ืŸ ืึท ืงืœื™ืง ืื•ื™ืฃ ื“ื™ ื“ืจื™ื˜ ืงื ืขืคึผืœ ืื•ื™ืฃ ื“ื™ ืœื™ื ืงืก ืื™ืŸ ื“ื™ ื”ื•ื™ืคึผื˜ ืžืขื ื™ื• ื•ื•ื™ื™ึทื˜ืขืจ ืฆื• ื“ื™ magnifying ื’ืœืื–.

ื“ืขืจ ืงื ืขืคึผืœ ืžื™ื˜ ืึท magnifying ื’ืœืื– ืึทืœืึทื•ื– ืื™ืจ ืฆื• ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ื“ื™ ื’ืขื‘ืขื˜ืŸ ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืคึฟืึทืจ ื‘ืึทื˜ืจืึทื›ื˜ื•ื ื’.

ืขืก ืื™ื– ื“ืขืจื•ื•ื™ื™ึทืœ ืงื™ื™ืŸ ืคื•ืœืฉื˜ืขื ื“ื™ืง ื”ื™ืœืฃ ืกื™ืกื˜ืขื. ื“ืขืจื™ื‘ืขืจ, ื“ืจื™ื ื’ืœืขืš ื“ื™ "?" ืงื ืขืคึผืœ ื•ื•ืขื˜ ืคืฉื•ื˜ ืคืึทืจืฉืึทืคืŸ ืึท ืžืึธื“ืึทืœ ืคึฟืขื ืฆื˜ืขืจ ืžื™ื˜ ื™ืงืขืจื“ื™ืง ืื™ื ืคึฟืึธืจืžืึทืฆื™ืข ื•ื•ืขื’ืŸ ื“ื™ ื•ื•ื™ื™ื›ื•ื•ืืจื’ ืคึผืจืึธื“ื•ืงื˜:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืŸ ืึทื“ื™ืฉืึทืŸ ืฆื• ืึทืœืฅ ื“ื™ืกืงืจื™ื™ื‘ื“ ืื•ื™ื‘ืŸ, ื“ื™ ื”ื•ื™ืคึผื˜ ืžืขื ื™ื• ื”ืื˜ ืึท ื–ื•ื›ืŸ ื‘ืึทืจ:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ื•ื•ืขืŸ ืื™ืจ ืึธื ื”ื™ื™ื‘ืŸ ื“ืขื ืื™ื ื“ืขืงืก ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ ืคึผืจืึธืฆืขืก:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืจ ืงืขื ื˜ ืื•ื™ืš ื–ืขืŸ ืึท ืงืœืึธืฅ ืคื•ืŸ ื“ื•ืจื›ื’ืขืงืึธื›ื˜ ืึทืงืฉืึทื ื– ืื™ืŸ ื“ื™ ื“ื ืึธ ืคื•ืŸ ื“ื™ ืคึฟืขื ืฆื˜ืขืจ:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืื™ืŸ ื“ื™ ื“ื™ื˜ื™ื™ืœื“ ืกืขื˜ื˜ื™ื ื’ืก ืคึฟืขื ืฆื˜ืขืจ ืคึฟืึทืจ ืื™ื ื“ืขืงืก ืึทื ืึทืœื™ืกื™ืก ืื•ืŸ ืึทืคึผื˜ืึทืžืึทื–ื™ื™ืฉืึทืŸ, ืื™ืจ ืงืขื ืขืŸ ืงืึทื ืคื™ื’ื™ืขืจ ืžืขืจ ืกืึทื˜ืึทืœ ืึธืคึผืฆื™ืขืก:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืจื™ืงื•ื•ืขืก ืคึฟืึทืจ ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ:

  1. ืžืึทื›ืŸ ืขืก ืžืขื’ืœืขืš ืฆื• ืกืึทืœืขืงื˜ื™ื•ื•ืœื™ ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงืŸ ืกื˜ืึทื˜ื™ืกื˜ื™ืง ื ื™ื˜ ื‘ืœื•ื™ื– ืคึฟืึทืจ ื™ื ื“ืขืงืกื™ื– ืื•ืŸ ืื•ื™ืš ืื™ืŸ ืคืึทืจืฉื™ื“ืขื ืข ื•ื•ืขื’ืŸ (ื’ืึธืจ ื“ืขืจื”ื™ื™ึทื ื˜ื™ืงืŸ ืึธื“ืขืจ ื˜ื™ื™ืœ)
  2. ืžืึทื›ืŸ ืขืก ืžืขื’ืœืขืš ื ื™ื˜ ื‘ืœื•ื™ื– ืฆื• ืื•ื™ืกืงืœื™ื™ึทื‘ืŸ ืึท ื“ืึทื˜ืึทื‘ื™ื™ืก, ืึธื‘ืขืจ ืื•ื™ืš ืคืึทืจืฉื™ื“ืขื ืข ืกืขืจื•ื•ืขืจืก (ื“ืึธืก ืื™ื– ื–ื™ื™ืขืจ ื‘ืึทืงื•ื•ืขื ื•ื•ืขืŸ ืขืก ื–ืขื ืขืŸ ืคื™ืœืข ื™ื ืกื˜ืึทื ืกื™ื– ืคื•ืŸ MS SQL Server)
  3. ืคึฟืึทืจ ืžืขืจ ื‘ื™ื™ื’ื™ืงื™ื™ื˜ ืื™ืŸ ื ื•ืฆืŸ, ืขืก ืื™ื– ืกืึทื’ื“ื–ืฉืขืกื˜ื™ื“ ืฆื• ื™ื™ึทื ื•ื•ื™ืงืœืขืŸ ื“ื™ ืงืึทืžืึทื ื“ื– ืื™ืŸ ืœื™ื™ื‘ืจืขืจื™ื– ืื•ืŸ ืึทืจื•ื™ืกืคื™ืจืŸ ื–ื™ื™ ืฆื• PowerShell ืงืึทืžืึทื ื“ื–, ื•ื•ื™ ืœืžืฉืœ, ื“ืึธ:
  4. dbatools.io/commands
  5. ืžืึทื›ืŸ ืขืก ืžืขื’ืœืขืš ืฆื• ืจืึทื˜ืขื•ื•ืขืŸ ืื•ืŸ ื˜ื•ื™ืฉืŸ ืคืขืจื–ืขื ืœืขื›ืข ืกืขื˜ื˜ื™ื ื’ืก ื‘ื™ื™ื“ืข ืคึฟืึทืจ ื“ื™ ื’ืื ืฆืข ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืื•ืŸ, ืื•ื™ื‘ ื ื™ื™ื˜ื™ืง, ืคึฟืึทืจ ื™ืขื“ืขืจ ื‘ื™ื™ึทืฉืคึผื™ืœ ืคื•ืŸ MS SQL Server ืื•ืŸ ื™ืขื“ืขืจ ื“ืึทื˜ืึทื‘ื™ื™ืก
  6. ืคึฟื•ืŸ ืคื•ื ืงื˜ืŸ 2 ืื•ืŸ 4, ืขืก ื’ื™ื™ื˜ ืึทื– ืื™ืจ ื•ื•ื™ืœืŸ ืฆื• ืฉืึทืคึฟืŸ ื’ืจื•ืคึผืขืก ื“ื•ืจืš ื“ืึทื˜ืึทื‘ื™ื™ืกื™ื– ืื•ืŸ ื’ืจื•ืคึผืขืก ื“ื•ืจืš MS SQL Server ื™ื ืกื˜ืึทื ืกื™ื–, ืคึฟืึทืจ ื•ื•ืึธืก ื“ื™ ืกืขื˜ื˜ื™ื ื’ืก ื–ืขื ืขืŸ ื“ื™ ื–ืขืœื‘ืข
  7. ื–ื•ื›ืŸ ืคึฟืึทืจ ื“ื•ืคึผืœื™ืงืึทื˜ ื™ื ื“ืขืงืกื™ื– (ื’ืึทื ืฅ ืื•ืŸ ื“ืขืจืขื ื“ื™ืงื˜, ื•ื•ืึธืก ื–ืขื ืขืŸ ืึท ื‘ื™ืกืœ ืึทื ื“ืขืจืฉ ืึธื“ืขืจ ืึทื ื“ืขืจืฉ ื‘ืœื•ื™ื– ืื™ืŸ ื“ื™ ืึทืจื™ื™ึทื ื’ืขืจืขื›ื ื˜ ืฉืคืืœื˜ืŸ)
  8. ื–ื™ื ื˜ SQLIndexManager ืื™ื– ื’ืขื ื™ืฆื˜ ื‘ืœื•ื™ื– ืคึฟืึทืจ MS SQL Server DBMS, ืขืก ืื™ื– ื ื™ื™ื˜ื™ืง ืฆื• ืคืึทืจื˜ืจืึทื›ื˜ื  ื“ืขื ื ืึธืžืขืŸ, ืœืžืฉืœ, ื•ื•ื™ ื’ื™ื™ื˜: SQLIndexManager ืคึฟืึทืจ MS SQL Server
  9. ืžืึทืš ืึทืœืข ื ื™ื˜-GUI ืคึผืึทืจืฅ ืคื•ืŸ ื“ื™ ืึทืคึผืœืึทืงื™ื™ืฉืึทืŸ ืื™ืŸ ื‘ืึทื–ื•ื ื“ืขืจ ืžืึทื“ื–ืฉื•ืœื– ืื•ืŸ ืจื™ืจื™ื™ื˜ ื–ื™ื™ ืื™ืŸ .NET Core 2.1

ืื™ืŸ ื“ืขืจ ืฆื™ื™ื˜ ืคื•ืŸ ืฉืจื™ื™ื‘ืŸ, ืคึผื•ื ืงื˜ 6 ืคื•ืŸ ื“ื™ ื•ื•ื™ืœ ืื™ื– ืึทืงื˜ื™ื•ื•ืœื™ ื“ืขื•ื•ืขืœืึธืคึผืขื“ ืื•ืŸ ืขืก ืื™ื– ืฉื•ื™ืŸ ืฉื˜ื™ืฆืŸ ืื™ืŸ ื“ืขืจ ืคืึธืจืขื ืคื•ืŸ ื–ื•ื›ืŸ ืคึฟืึทืจ ื’ืึทื ืฅ ืื•ืŸ ืขื ืœืขืš ื“ื•ืคึผืœื™ืงืึทื˜ืŸ:

ืจืขืฆืขื ื–ื™ืข ืคื•ืŸ โ€‹โ€‹ื“ื™ ืคืจื™ื™ ื’ืขืฆื™ื™ึทื’ SQLIndexManager

ืงื•ื•ืืœืŸ

ืžืงื•ืจ: www.habr.com

ืœื™ื™ื’ืŸ ืึท ื‘ืึทืžืขืจืงื•ื ื’