प्रस्तावना
वर्ल्ड वाइड वेब SQL सर्वर इंडेक्स डीफ़्रेग्मेंटेशन या SQL सर्वर इंडेक्स पुनर्निर्माण पर जानकारी का एक गुच्छा प्रदान करता है। हालाँकि, अधिकांश अनुशंसाएँ उन डेटाबेसों को संदर्भित करती हैं जिनमें न्यूनतम लोड समय (ज्यादातर, रात में) होता है।
और उन डेटाबेस के बारे में क्या जिनका उपयोग डेटा संशोधन और 24/7 आधार पर जानकारी प्राप्त करने के लिए किया जाता है?
इस लेख में, मैं जिस कंपनी के लिए काम करता हूं उसमें उपयोग किए गए डेटाबेस में कार्यान्वित SQL सर्वर इंडेक्स डीफ़्रैग्मेन्टेशन को स्वचालित करने के लिए एक तंत्र प्रदान करूंगा। यह तंत्र नियमित आधार पर आवश्यक इंडेक्स को डीफ़्रैग्मेन्ट करने की अनुमति देता है क्योंकि 24/7 सिस्टम में इंडेक्स फ़्रेग्मेंटेशन लगातार होता रहता है। अक्सर, यह दिन में एक बार इंडेक्स डीफ़्रैग्मेन्टेशन करने के लिए पर्याप्त नहीं होता है।
समाधान
सबसे पहले, आइए सामान्य दृष्टिकोण पर एक नज़र डालें:
- एक दृश्य बनाना जिसमें दिखाया गया है कि कौन से अनुक्रमित खंडित किए गए हैं और खंडित अनुक्रमणिका का प्रतिशत।
- सूचकांक डीफ़्रैग्मेन्टेशन परिणामों को संग्रहीत करने के लिए एक तालिका बनाना।
- चयनित अनुक्रमणिका का विश्लेषण और डीफ़्रैग्मेन्ट करने के लिए एक संग्रहीत कार्यविधि बनाना।
- सूचकांक डीफ़्रेग्मेंटेशन परिणामों के आंकड़े देखने के लिए एक दृश्य बनाना।
- कार्यान्वित संग्रहीत कार्यविधि को चलाने के लिए एजेंट में एक कार्य बनाना।
और अब, कार्यान्वयन पर एक नज़र डालते हैं:
1. एक दृश्य बनाना जिसमें दिखाया गया है कि कौन सी अनुक्रमणिका खंडित हो गई है और खंडित अनुक्रमणिका का प्रतिशत:
USE [Database_Name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE view [srv].[vIndexDefrag]
as
with info as
(SELECT
[object_id],
database_id,
index_id,
index_type_desc,
index_level,
fragment_count,
avg_fragmentation_in_percent,
avg_fragment_size_in_pages,
page_count,
record_count,
ghost_record_count
FROM sys.dm_db_index_physical_stats
(DB_ID(N'Database_Name')
, NULL, NULL, NULL ,
N'DETAILED')
where index_level = 0
)
SELECT
b.name as db,
s.name as shema,
t.name as tb,
i.index_id as idx,
i.database_id,
idx.name as index_name,
i.index_type_desc,i.index_level as [level],
i.[object_id],
i.fragment_count as frag_num,
round(i.avg_fragmentation_in_percent,2) as frag,
round(i.avg_fragment_size_in_pages,2) as frag_page,
i.page_count as [page],
i.record_count as rec,
i.ghost_record_count as ghost,
round(i.avg_fragmentation_in_percent*i.page_count,0) as func
FROM Info as i
inner join [sys].[databases] as b on i.database_id = b.database_id
inner join [sys].[all_objects] as t on i.object_id = t.object_id
inner join [sys].[schemas] as s on t.[schema_id] = s.[schema_id]
inner join [sys].[indexes] as idx on t.object_id = idx.object_id and idx.index_id = i.index_id
where i.avg_fragmentation_in_percent >= 30 and i.index_type_desc <> 'HEAP';
GO यह दृश्य केवल 30 से अधिक फ़्रेग्मेंटेशन प्रतिशत वाले इंडेक्स दिखाता है, यानी ऐसे इंडेक्स जिन्हें डीफ़्रैग्मेन्टेशन की आवश्यकता होती है। यह केवल इंडेक्स दिखाता है जो ढेर नहीं हैं, क्योंकि बाद वाले नकारात्मक प्रभाव पैदा कर सकते हैं, जैसे इस तरह के ढेर को अवरुद्ध करना, या आगे इंडेक्स विखंडन।
दृश्य महत्वपूर्ण सिस्टम दृश्य sys.dm_db_index_physical_stats का उपयोग करता है।
2. अनुक्रमणिका डीफ़्रेग परिणामों को संग्रहीत करने के लिए तालिका बनाना:
USE [Database_Name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [srv].[Defrag](
[ID] [bigint] IDENTITY(794,1) NOT NULL,
[db] [nvarchar](100) NULL,
[shema] [nvarchar](100) NULL,
[table] [nvarchar](100) NULL,
[IndexName] [nvarchar](100) NULL,
[frag_num] [int] NULL,
[frag] [decimal](6, 2) NULL,
[page] [int] NULL,
[rec] [int] NULL,
[func] [int] NULL,
[ts] [datetime] NULL,
[tf] [datetime] NULL,
[frag_after] [decimal](6, 2) NULL,
[object_id] [int] NULL,
[idx] [int] NULL,
[InsertUTCDate] [datetime] NOT NULL,
CONSTRAINT [PK_Defrag] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY];
GO
ALTER TABLE [srv].[Defrag] ADD CONSTRAINT [DF_Defrag_InsertUTCDate] DEFAULT (getutcdate()) FOR [InsertUTCDate];
GO इस तालिका के बारे में सबसे महत्वपूर्ण बात डेटा हटाने को ध्यान में रखना है (उदाहरण के लिए, डेटा जो 1 महीने से अधिक पुराना है)।
टेबल फ़ील्ड अगले बिंदु से समझने योग्य हो जाएंगे।
3. चयनित इंडेक्स का विश्लेषण और डीफ़्रैग्मेन्ट करने के लिए एक संग्रहीत कार्यविधि बनाना:
USE [Database_Name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [srv].[AutoDefragIndex]
AS
BEGIN
SET NOCOUNT ON;
--declaring required variables
declare @IndexName nvarchar(100) --index name
,@db nvarchar(100) --database name
,@Shema nvarchar(100) --schema name
,@Table nvarchar(100) --table name
,@SQL_Str nvarchar (2000) --string for command generation
,@frag decimal(6,2) --fragmentation percentage before defragmentation
,@frag_after decimal(6,2) --fragmentation percentage after defragmentation
--Number of fragments at the final level of the IN_ROW_DATA allocation unit
,@frag_num int
,@func int --round(i.avg_fragmentation_in_percent*i.page_count,0)
,@page int --number of index pages
,@rec int --total number of records
,@ts datetime --date and time of defragmentation start
,@tf datetime --date and time of defragmenation finish
--Table or view object ID for which the index was created
,@object_id int
,@idx int; --index ID
--getting current date and time
set @ts = getdate();
--getting next index for defragmenation
--Here the important index is selected. At that, a situation when one index is defragmented regularly, while other indexes are not selected for defragmentation is unlikely.
select top 1
@IndexName = index_name,
@db=db,
@Shema = shema,
@Table = tb,
@frag = frag,
@frag_num = frag_num,
@func=func,
@page =[page],
@rec = rec,
@object_id = [object_id],
@idx = idx
from [srv].[vIndexDefrag]
order by func*power((1.0-
convert(float,(select count(*) from SRV.[srv].[Defrag] vid where vid.db=db
and vid.shema = shema
and vid.[table] = tb
and vid.IndexName = index_name))
/
convert(float,
case when (exists (select top 1 1 from SRV.[srv].[Defrag] vid1 where vid1.db=db))
then (select count(*) from SRV.[srv].[Defrag] vid1 where vid1.db=db)
else 1.0 end))
,3) desc
--if we get such index
if(@db is not null)
begin
--index reorganization
set @SQL_Str = 'alter index ['example@sqldat.com+'] on ['example@sqldat.com+'].['example@sqldat.com+'] Reorganize';
execute sp_executesql @SQL_Str;
--getting current date and time
set @tf = getdate()
--getting fragmentation percentage after defragmentation
SELECT @frag_after = avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats
(DB_ID(@db), @object_id, @idx, NULL ,
N'DETAILED')
where index_level = 0;
--writing the result of work
insert into SRV.srv.Defrag(
[db],
[shema],
[table],
[IndexName],
[frag_num],
[frag],
[page],
[rec],
ts,
tf,
frag_after,
object_id,
idx
)
select
@db,
@shema,
@table,
@IndexName,
@frag_num,
@frag,
@page,
@rec,
@ts,
@tf,
@frag_after,
@object_id,
@idx;
--upating statistics for index
set @SQL_Str = 'UPDATE STATISTICS ['example@sqldat.com+'].['example@sqldat.com+'] ['example@sqldat.com+']';
execute sp_executesql @SQL_Str;
end
END 4. सूचकांक डीफ़्रेग्मेंटेशन परिणामों के आंकड़े देखने के लिए एक दृश्य बनाना:
USE [Database_Name]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE view [srv].[vStatisticDefrag] as
SELECT top 1000
[db]
,[shema]
,[table]
,[IndexName]
,avg([frag]) as AvgFrag
,avg([frag_after]) as AvgFragAfter
,avg(page) as AvgPage
FROM [srv].[Defrag]
group by [db], [shema], [table], [IndexName]
order by abs(avg([frag])-avg([frag_after])) desc;
GO इस दृश्य का उपयोग प्रतिदिन प्रशासकों को अनुक्रमणिका डीफ़्रेग्मेंटेशन स्वचालन के परिणामों के बारे में सूचित करने के लिए किया जा सकता है।
5. क्रियान्वित संग्रहीत कार्यविधि को चलाने के लिए एजेंट में कार्य बनाना
यहां, हमें प्रायोगिक तरीके से समय चुनने की जरूरत है। मेरे मामले में, कहीं मुझे 5 मिनट मिले, कहीं-1 घंटे।
इस एल्गोरिथम को कई डेटाबेस पर विस्तारित किया जा सकता है, लेकिन इस मामले में, हमें एक अतिरिक्त बिंदु 6 की आवश्यकता है:
बाद में प्रशासकों को भेजने के लिए इंडेक्स डीफ़्रेग्मेंटेशन ऑटोमेशन के सभी आंकड़ों को एक स्थान पर एकत्रित करना।
और अब, मैं सूचकांक समर्थन के लिए पहले से प्रदान की गई सिफारिशों पर ध्यान देना चाहूंगा:
- न्यूनतम डेटाबेस लोड के दौरान सभी इंडेक्स का एक साथ डीफ़्रैग्मेन्टेशन 24/7 सिस्टम के लिए अस्वीकार्य है, क्योंकि इंडेक्स लगातार खंडित होते हैं और डेटाबेस के निष्क्रिय रहने का लगभग कोई समय नहीं होता है।
- SQL सर्वर अनुक्रमणिका पुनर्गठन - यह ऑपरेशन एक तालिका या विभाजन को अवरुद्ध करता है (विभाजित अनुक्रमणिका के मामले में), जो 24/7 सिस्टम के लिए अच्छा नहीं है। फिर, रीयल-टाइम मोड में अनुक्रमणिका पुनर्निर्माण केवल एंटरप्राइज़ समाधान में समर्थित है, और इससे डेटा को नुकसान भी हो सकता है।
यह विधि इष्टतम नहीं है, लेकिन यह सुनिश्चित करने में सफलतापूर्वक सामना कर सकती है कि निष्पादन योजनाओं के निर्माण के लिए ऑप्टिमाइज़र द्वारा उनके बाद के उपयोग के लिए अनुक्रमणिका ठीक से डीफ़्रैग्मेन्टेड (विखंडन के 30-40% से अधिक नहीं) हैं।
मैं इस दृष्टिकोण के तर्कपूर्ण पक्ष और विपक्ष के साथ-साथ परीक्षण किए गए वैकल्पिक सुझावों के लिए आपकी टिप्पणियों के लिए आभारी रहूंगा।
संदर्भ
- सूचकांकों को पुनर्व्यवस्थित और पुनर्निर्माण करें
- sys.dm_db_index_physical_stats
उपयोगी टूल:
डीबीफोर्ज इंडेक्स मैनेजर - एसक्यूएल इंडेक्स की स्थिति का विश्लेषण करने और इंडेक्स विखंडन के साथ मुद्दों को ठीक करने के लिए आसान एसएसएमएस ऐड-इन।