Wongororo yemahara chishandiso SQLIndexManager

Sezvaunoziva, indexes inoita basa rinokosha muDBMS, ichipa kukurumidza kutsvaga kune zvinyorwa zvinodiwa. Ndicho chikonzero nei zvakakosha kuti vashandise panguva yakakodzera. Zvakawanda zvezvinhu zvakanyorwa pamusoro pekuongorora uye optimization, kusanganisira paInternet. Semuenzaniso, nyaya iyi yakaongororwa munguva pfupi yapfuura chinyorwa ichi.

Kune dzakawanda dzakabhadharwa uye dzemahara mhinduro dzeizvi. Somuenzaniso, pane yakagadzirira-yakagadzirwa mhinduro, zvichibva pane inogadzirisa index optimization nzira.

Tevere, ngatitarisei kune yemahara utility SQLIndexManager, rakanyorwa na AlanDenton.

Musiyano mukuru wehunyanzvi pakati peSQLIndexManager uye akati wandei mamwe analogues anopiwa nemunyori pachake pano ΠΈ pano.

Muchikamu chino, tichatarisa kunze kweprojekti uye kugona kwekuita kweiyi software mhinduro.

Kukurukura nezvechishandiso ichi pano.
Nekufamba kwenguva, mazhinji emashoko netsikidzi zvakagadziriswa.

Saka, ngatichiendai kuSQLIndexManager utility pachayo.

Chikumbiro chakanyorwa muC# .NET Framework 4.5 muVisual Studio 2017 uye inoshandisa DevExpress yemafomu:

Wongororo yemahara chishandiso SQLIndexManager

uye zvinotaridzika seizvi:

Wongororo yemahara chishandiso SQLIndexManager

Zvese zvikumbiro zvinogadzirwa mumafaira anotevera:

  1. indekisi
  2. Query
  3. QueryEngine
  4. ServerInfo

Wongororo yemahara chishandiso SQLIndexManager

Kana uchibatanidza kune dhatabhesi uye kutumira mibvunzo kuDBMS, chikumbiro chinosainwa sezvizvi:

ApplicationName=”SQLIndexManager”

Paunotangisa application, modal hwindo rinovhurwa kuti uwedzere chinongedzo:
Wongororo yemahara chishandiso SQLIndexManager

Pano, kurodha runyorwa rwakazara rweese MS SQL Server zviitiko zvinosvikika pamusoro penzvimbo network hazvisati zvashanda.

Iwe unogona zvakare kuwedzera chinongedzo uchishandisa bhatani rekuruboshwe pane iyo huru menyu:

Wongororo yemahara chishandiso SQLIndexManager

Tevere, iyo inotevera mibvunzo kuDBMS ichatangwa:

  1. Kuwana ruzivo nezve DBMS
    SELECT ProductLevel  = SERVERPROPERTY('ProductLevel')
         , Edition       = SERVERPROPERTY('Edition')
         , ServerVersion = SERVERPROPERTY('ProductVersion')
         , IsSysAdmin    = CAST(IS_SRVROLEMEMBER('sysadmin') AS BIT)
    

  2. Kuwana runyoro rwemadhatabhesi aripo ane mapfupi zvivakwa
    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
    

Mushure mekuita zvinyorwa zviri pamusoro, hwindo richaonekwa rine ruzivo rupfupi nezve dhatabhesi yemuenzaniso wakasarudzwa weMS SQL Server:

Wongororo yemahara chishandiso SQLIndexManager

Zvakakosha kuziva kuti ruzivo rwakawedzerwa runoratidzwa maererano nekodzero. Kana aripo sysadmin, ipapo unogona kusarudza data kubva pakuona sys.master_files. Kana pasina kodzero dzakadaro, saka data shoma inongodzoserwa kuitira kuti isanonoka kukumbira.

Pano iwe unofanirwa kusarudza iyo dhatabhesi yekufarira uye tinya pane "OK" bhatani.

Tevere, iyo inotevera script ichaitwa kune yega yega yakasarudzwa dhatabhesi kuti iongorore mamiriro eiyo indexes:

Index mamiriro ekuongorora

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

Sezvinoonekwa kubva kumibvunzo pachayo, matafura enguva pfupi anoshandiswa kazhinji. Izvi zvinoitwa kuitira kuti pasave nekudzoreredzwa, uye kana iri chirongwa chakakura, chirongwa chinogona kugadzirwa chakafanana kana uchiisa data, sezvo kuisa tafura kuchinjika kunogoneka chete mune imwe shinda.

Mushure mekuita script iri pamusoro, hwindo rine index index richaonekwa:

Wongororo yemahara chishandiso SQLIndexManager

Iwe unogona zvakare kuratidza rumwe ruzivo rwakadzama pano, senge:

  1. database
  2. nhamba yezvikamu
  3. zuva uye nguva yekupedzisira kufona
  4. kudzvinyirira
  5. filegroup

uye zvakadaro.
Vatauri pachavo vanogona kugadzirwa:

Wongororo yemahara chishandiso SQLIndexManager

Mune maseru eiyo Fix column, unogona kusarudza kuti ndechipi chiito chichaitwa panguva yekugadzirisa. Zvakare, kana scan yapera, chiito chekare chinosarudzwa zvichibva pane zvakasarudzwa marongero:

Wongororo yemahara chishandiso SQLIndexManager

Iwe unofanirwa kusarudza iwo anodiwa ma indexes ekugadzirisa.

Uchishandisa iyo huru menyu, unogona kuchengetedza script (iyo bhatani rimwechete rinotanga iyo index optimization process pachayo):

Wongororo yemahara chishandiso SQLIndexManager

uye chengetedza tafura mumafomati akasiyana (bhatani rimwe chete rinokutendera kuti uvhure marongero akadzama ekuongorora uye nekugadzirisa indexes):

Wongororo yemahara chishandiso SQLIndexManager

Iwe unogona zvakare kugadzirisa ruzivo nekudzvanya bhatani rechitatu kuruboshwe mumenyu huru padyo negirazi rinokudza.

Bhatani rine girazi rinokudza rinokubvumira kuti usarudze dhatabhesi raunoda kuti utarise.

Parizvino hapana hurongwa hwekubatsira hwakakwana. Naizvozvo, kudzvanya bhatani "?" zvinongokonzera kuti modal hwindo rioneke riine ruzivo rwekutanga nezve software chigadzirwa:

Wongororo yemahara chishandiso SQLIndexManager

Pamusoro pezvese zvakatsanangurwa pamusoro, iyo huru menyu ine bhari yekutsvaga:

Wongororo yemahara chishandiso SQLIndexManager

Kana uchitanga iyo index optimization process:

Wongororo yemahara chishandiso SQLIndexManager

Iwe unogona zvakare kuona chinyorwa chezviito zvakaitwa pazasi pehwindo:

Wongororo yemahara chishandiso SQLIndexManager

Mune yakadzama zvigadziriso hwindo rekuongorora index uye optimization, unogona kugadzirisa dzimwe dzisiri sarudzo:

Wongororo yemahara chishandiso SQLIndexManager

Zvikumbiro zvekushandisa:

  1. ita kuti zvikwanisike kugadzirisa zviverengero zvakasarudzwa kwete zve indexes chete uye zvakare nenzira dzakasiyana (kunyatso gadziridza kana zvishoma)
  2. ita kuti zvikwanise kwete chete kusarudza dhatabhesi, asiwo akasiyana maseva (izvi zviri nyore kana paine akawanda mameseji eMS SQL Server)
  3. Kuti uwedzere kushanduka mukushandiswa, zvinokurudzirwa kuputira mirairo mumaraibhurari uye kuiburitsa kune PowerShell mirairo, sezvaiitwa, semuenzaniso, pano:
  4. dbatools.io/commands
  5. ita kuti zvikwanise kuchengetedza uye kushandura zvigadziriso zvemunhu zvese zvechishandiso chose uye, kana zvichidikanwa, kune yega yega chiitiko cheMS SQL Server uye yega yega dhatabhesi.
  6. Kubva pamapoinzi 2 ne4, zvinotevera kuti iwe unoda kugadzira mapoka nemadhatabhesi uye mapoka neMS SQL Server zviitiko, izvo zvigadziriso zvakafanana.
  7. tsvaga maduplicate indexes (akazara uye asina kukwana, ayo angave akasiyana zvishoma kana akasiyana chete mumakoramu akabatanidzwa)
  8. Sezvo SQLIndexManager ichishandiswa chete kuMS SQL Server DBMS, zvinodikanwa kuratidza izvi muzita, semuenzaniso, sezvinotevera: SQLIndexManager yeMS SQL Server.
  9. Fambisa zvikamu zvese zvisiri zveGUI zvekushandisa mumamodule akaparadzana wozvinyora zvakare muNET Core 2.1

Panguva yekunyora, chinhu chechitanhatu chezvishuwo chiri kuvandudzwa uye patove nerutsigiro nenzira yekutsvaga yakakwana uye yakafanana kopi:

Wongororo yemahara chishandiso SQLIndexManager

Sources

Source: www.habr.com

Voeg