๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

์•„์‹œ๋‹ค์‹œํ”ผ ์ธ๋ฑ์Šค๋Š” DBMS์—์„œ ํ•„์š”ํ•œ ๋ ˆ์ฝ”๋“œ๋ฅผ ๋น ๋ฅด๊ฒŒ ๊ฒ€์ƒ‰ํ•˜๋Š” ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ์ ์‹œ์— ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์ธํ„ฐ๋„ท์„ ํฌํ•จํ•˜์—ฌ ๋ถ„์„ ๋ฐ ์ตœ์ ํ™”์— ๊ด€ํ•œ ๋งŽ์€ ์ž๋ฃŒ๊ฐ€ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด ์ฃผ์ œ๋Š” ์ตœ๊ทผ์— ๊ฒ€ํ† ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฐ„ํ–‰๋ฌผ.

์ด์— ๋Œ€ํ•œ ๋งŽ์€ ์œ ๋ฃŒ ๋ฐ ๋ฌด๋ฃŒ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ๊ธฐ์„ฑํ’ˆ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ์ •, ์ ์‘ํ˜• ์ธ๋ฑ์Šค ์ตœ์ ํ™” ๋ฐฉ๋ฒ•์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ ๋ฌด๋ฃŒ ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SQLIndexManager, ์ž‘์„ฑ์ž: ์•จ๋Ÿฐ๋ดํ„ด.

SQLIndexManager์™€ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ์œ ์‚ฌ์ฒด ๊ฐ„์˜ ์ฃผ์š” ๊ธฐ์ˆ ์  ์ฐจ์ด์ ์€ ์ž‘์„ฑ์ž๊ฐ€ ์ง์ ‘ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ะธ ์—ฌ๊ธฐ์—.

์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ํ”„๋กœ์ ํŠธ์™€ ์ด ์†Œํ”„ํŠธ์›จ์–ด ์†”๋ฃจ์…˜์˜ ์šด์˜ ๊ธฐ๋Šฅ์„ ์™ธ๋ถ€์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ์œ ํ‹ธ๋ฆฌํ‹ฐ์— ๋Œ€ํ•ด ๋…ผ์˜ํ•˜๊ธฐ ์—ฌ๊ธฐ์—.
์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด์„œ ๋Œ€๋ถ€๋ถ„์˜ ๋Œ“๊ธ€๊ณผ ๋ฒ„๊ทธ๊ฐ€ ์ˆ˜์ •๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ SQLIndexManager ์œ ํ‹ธ๋ฆฌํ‹ฐ ์ž์ฒด์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ Visual Studio 4.5์˜ C# .NET Framework 2017๋กœ ์ž‘์„ฑ๋˜์—ˆ์œผ๋ฉฐ ์–‘์‹์— DevExpress๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณด์ž…๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

๋ชจ๋“  ์š”์ฒญ์€ ๋‹ค์Œ ํŒŒ์ผ์—์„œ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.

  1. ์ƒ‰์ธ
  2. ์งˆ๋ฌธ
  3. ์ฟผ๋ฆฌ์—”์ง„
  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. ํŒŒ์ผ ๊ทธ๋ฃน

๊ทธ๋ฆฌ๊ณ  t. ๋ผ.
์Šคํ”ผ์ปค ์ž์ฒด๋ฅผ ๋งž์ถค ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

์ˆ˜์ • ์—ด์˜ ์…€์—์„œ ์ตœ์ ํ™” ์ค‘์— ์ˆ˜ํ–‰ํ•  ์ž‘์—…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฒ€์‚ฌ๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ์„ ํƒํ•œ ์„ค์ •์— ๋”ฐ๋ผ ๊ธฐ๋ณธ ์ž‘์—…์ด ์„ ํƒ๋ฉ๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ์›ํ•˜๋Š” ์ธ๋ฑ์Šค๋ฅผ ์„ ํƒํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๋ฉ”๋‰ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค(๋™์ผํ•œ ๋ฒ„ํŠผ์œผ๋กœ ์ธ๋ฑ์Šค ์ตœ์ ํ™” ํ”„๋กœ์„ธ์Šค ์ž์ฒด๊ฐ€ ์‹œ์ž‘๋ฉ๋‹ˆ๋‹ค).

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

ํ…Œ์ด๋ธ”์„ ๋‹ค์–‘ํ•œ ํ˜•์‹์œผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค(๋™์ผํ•œ ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ธ๋ฑ์Šค ๋ถ„์„ ๋ฐ ์ตœ์ ํ™”๋ฅผ ์œ„ํ•œ ์„ธ๋ถ€ ์„ค์ •์„ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค).

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

๋ฉ”์ธ ๋ฉ”๋‰ด์˜ ๋‹๋ณด๊ธฐ ์˜†์— ์žˆ๋Š” ์™ผ์ชฝ ์„ธ ๋ฒˆ์งธ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜์—ฌ ์ •๋ณด๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹๋ณด๊ธฐ๊ฐ€ ์žˆ๋Š” ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ณ ๋ คํ•  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ํฌ๊ด„์ ์ธ ๋„์›€๋ง ์‹œ์Šคํ…œ์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ โ€œ?โ€ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์†Œํ”„ํŠธ์›จ์–ด ์ œํ’ˆ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ ๋ชจ๋‹ฌ ์ฐฝ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ 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 for MS SQL Server
  9. ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ GUI๊ฐ€ ์•„๋‹Œ ๋ชจ๋“  ๋ถ€๋ถ„์„ ๋ณ„๋„์˜ ๋ชจ๋“ˆ๋กœ ์ด๋™ํ•˜๊ณ  .NET Core 2.1์—์„œ ๋‹ค์‹œ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

์ด ๊ธ€์„ ์“ฐ๋Š” ์‹œ์ ์—์„œ ์†Œ์› ํ•ญ๋ชฉ 6์ด ํ™œ๋ฐœํžˆ ๊ฐœ๋ฐœ๋˜๊ณ  ์žˆ์œผ๋ฉฐ ์™„์ „ํ•˜๊ณ  ์œ ์‚ฌํ•œ ์ค‘๋ณต ํ•ญ๋ชฉ์„ ๊ฒ€์ƒ‰ํ•˜๋Š” ํ˜•ํƒœ๋กœ ์ด๋ฏธ ์ง€์›์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌด๋ฃŒ ๋„๊ตฌ SQLIndexManager ๊ฒ€ํ† 

์†Œ์Šค

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€