SQL सर्वर DBA के रूप में, हम हमेशा व्यवसाय के लिए सबसे महत्वपूर्ण चीजों में से एक, डेटा का ध्यान रखते हैं। कुछ मामलों में, एप्लिकेशन काफी जटिल हो सकते हैं, और आप अपने SQL सर्वर इंस्टेंस के चारों ओर बिखरे हुए डेटाबेस तालिकाओं के एक टन के साथ समाप्त होते हैं। इससे कुछ असुविधाएँ हो सकती हैं, जैसे:
- विकास प्रवृत्तियों (स्थान और/या पंक्तियों की मात्रा) के संदर्भ में यह जानना कि आपका डेटा प्रतिदिन कैसा व्यवहार करता है।
- जानते हुए कि डेटा को स्टोर करने के लिए डेटाबेस टेबल को किस विशेष/अलग रणनीति की आवश्यकता होती है (या आवश्यकता होगी) क्योंकि यह बहुत तेजी से बढ़ रहा है।
- यह जानना कि आपकी कौन सी डेटाबेस तालिकाएँ बहुत अधिक स्थान लेती हैं, संभवतः संग्रहण बाधाओं का कारण बन सकती हैं।
इन विवरणों के महत्व के कारण, मैंने कुछ संग्रहीत कार्यविधियाँ बनाई हैं जो किसी भी SQL सर्वर DBA के लिए बहुत मददगार हो सकती हैं जो अपने वातावरण में डेटाबेस तालिकाओं के बारे में जानकारी का ट्रैक रखना चाहते हैं। मेरा विश्वास करो, उनमें से एक बहुत अच्छा है।
प्रारंभिक विचार
- सुनिश्चित करें कि इस संग्रहीत प्रक्रिया को निष्पादित करने वाले खाते में पर्याप्त विशेषाधिकार हैं। आप शायद sysadmin से शुरू कर सकते हैं और फिर यह सुनिश्चित करने के लिए जितना संभव हो उतना बारीक जा सकते हैं कि उपयोगकर्ता के पास एसपी के ठीक से काम करने के लिए आवश्यक न्यूनतम विशेषाधिकार हैं।
- डेटाबेस ऑब्जेक्ट (डेटाबेस तालिका और संग्रहीत कार्यविधि) स्क्रिप्ट निष्पादित होने के समय चयनित डेटाबेस के अंदर बनाए जाएंगे, इसलिए सावधानी से चुनें।
- स्क्रिप्ट को इस तरह से तैयार किया गया है कि आप पर कोई त्रुटि डाले बिना इसे कई बार निष्पादित किया जा सकता है। संग्रहीत कार्यविधि के लिए, मैंने SQL सर्वर 2016 SP1 के बाद से उपलब्ध "CREATE OR ALTER PROCEDURE" कथन का उपयोग किया। इसलिए आश्चर्यचकित न हों अगर यह पुराने संस्करण में सुचारू रूप से काम नहीं करता है।
- बनाए गए डेटाबेस ऑब्जेक्ट के नाम बदलने के लिए स्वतंत्र महसूस करें।
- संग्रहीत प्रक्रिया के मापदंडों पर ध्यान दें जो कच्चा डेटा एकत्र करता है। रुझानों की कल्पना करने के लिए वे एक शक्तिशाली डेटा-संग्रह रणनीति में महत्वपूर्ण हो सकते हैं।
संग्रहीत कार्यविधियों का उपयोग कैसे करें?
- टी-एसक्यूएल कोड को कॉपी और पेस्ट करें (इस लेख में उपलब्ध)।
- पहला एसपी 2 मापदंडों की अपेक्षा करता है:
- @पर्सिस्टडेटा:'Y' यदि कोई DBA लक्ष्य तालिका में आउटपुट को सहेजना चाहता है, और 'N' यदि DBA सीधे आउटपुट देखना चाहता है।
- @truncateTable:कैप्चर किए गए डेटा को स्टोर करने से पहले पहले टेबल को छोटा करने के लिए 'Y', और अगर मौजूदा डेटा को टेबल में रखा जाता है तो 'N'। ध्यान रखें कि यदि @persistData पैरामीटर का मान 'N' है तो इस पैरामीटर का मान अप्रासंगिक है।
- दूसरा SP 1 पैरामीटर की अपेक्षा करता है:
- @targetParameter:एकत्रित जानकारी को स्थानांतरित करने के लिए उपयोग किए जाने वाले कॉलम का नाम।
प्रस्तुत किए गए फ़ील्ड और उनके अर्थ
- डेटाबेस_नाम: उस डेटाबेस का नाम जहां तालिका रहती है।
- स्कीमा: स्कीमा का नाम जहां तालिका रहती है।
- table_name: तालिका के नाम के लिए प्लेसहोल्डर।
- row_count: तालिका में वर्तमान में मौजूद पंक्तियों की संख्या।
- total_space_mb: तालिका के लिए आवंटित मेगाबाइट की संख्या।
- used_space_mb: तालिका द्वारा वास्तव में उपयोग किए जाने वाले मेगाबाइट की संख्या।
- unused_space_mb: मेगाबाइट की संख्या जिसका तालिका उपयोग नहीं कर रही है।
- बनाई गई तारीख: दिनांक/समय जब तालिका बनाई गई थी।
- data_collection_timestamp: केवल तभी दिखाई देता है जब 'Y' @persistData पैरामीटर को पास किया जाता है। इसका उपयोग यह जानने के लिए किया जाता है कि SP को कब निष्पादित किया गया था और जानकारी को DBA_Tables तालिका में सफलतापूर्वक सहेजा गया था।
निष्पादन परीक्षण
मैं संग्रहित प्रक्रियाओं के कुछ निष्पादन प्रदर्शित करूंगा:
/* सभी उपयोगकर्ता डेटाबेस के लिए तालिकाओं की जानकारी प्रदर्शित करें */
EXEC GetTablesData @persistData = 'N',@truncateTable = 'N'
/* डेटाबेस तालिकाओं की जानकारी जारी रखें और लक्ष्य तालिका को क्वेरी करें, पहले लक्ष्य तालिका को छोटा करें */
EXEC GetTablesData @persistData = 'Y',@truncateTable = 'Y'
SELECT * FROM DBA_Tables
साइड क्वेरी
*डेटाबेस तालिका को देखने की क्वेरी सबसे बड़ी संख्या में पंक्तियों से सबसे कम तक क्रमबद्ध है।
SELECT * FROM DBA_Tables ORDER BY row_count DESC;
*डेटाबेस तालिका को देखने के लिए क्वेरी को सबसे बड़े कुल स्थान से निम्नतम तक क्रमबद्ध किया गया।
SELECT * FROM DBA_Tables ORDER BY total_space_mb DESC;
*सबसे बड़े उपयोग किए गए स्थान से निम्नतम तक क्रमबद्ध डेटाबेस तालिकाओं को देखने के लिए क्वेरी।
SELECT * FROM DBA_Tables ORDER BY used_space_mb DESC;
*सबसे बड़े अप्रयुक्त स्थान से निम्नतम तक क्रमबद्ध डेटाबेस तालिकाओं को देखने की क्वेरी।
SELECT * FROM DBA_Tables ORDER BY unused_space_mb DESC;
*नवीनतम से सबसे पुरानी तक, निर्माण तिथि के अनुसार क्रमबद्ध डेटाबेस तालिकाओं को देखने की क्वेरी।
SELECT * FROM DBA_Tables ORDER BY created_date DESC;
यहां संग्रहीत प्रक्रिया का एक पूरा कोड है जो डेटाबेस तालिकाओं की जानकारी को कैप्चर करता है:
*स्क्रिप्ट की शुरुआत में, आप डिफ़ॉल्ट मान देखेंगे जिसे संग्रहीत प्रक्रिया मानती है यदि प्रत्येक पैरामीटर के लिए कोई मान पास नहीं किया जाता है।
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER PROCEDURE [dbo].[GetTablesData]
@persistData CHAR(1) = 'Y',
@truncateTable CHAR(1) = 'Y'
AS
BEGIN
SET NOCOUNT ON
DECLARE @command NVARCHAR(MAX)
DECLARE @Tmp_TablesInformation TABLE(
[database] [VARCHAR](255) NOT NULL,
[schema] [VARCHAR](64) NOT NULL,
[table] [VARCHAR](255) NOT NULL,
[row_count] [BIGINT]NOT NULL,
[total_space_mb] [DECIMAL](15,2) NOT NULL,
[used_space_mb] [DECIMAL](15,2) NOT NULL,
[unused_space_mb] [DECIMAL](15,2) NOT NULL,
[created_date] [DATETIME] NOT NULL
)
SELECT @command = '
USE [?]
IF DB_ID(''?'') > 4
BEGIN
SELECT
''?'',
s.Name AS [schema],
t.NAME AS [table],
p.rows AS row_count,
CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2) AS DECIMAL(15, 2)) AS total_space_mb,
CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2) AS DECIMAL(15, 2)) AS used_space_mb,
CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2) AS DECIMAL(15, 2)) AS unused_space_mb,
t.create_date as created_date
FROM sys.tables t
INNER JOIN sys.indexes i ON t.OBJECT_ID = i.object_id
INNER JOIN sys.partitions p ON i.object_id = p.OBJECT_ID AND i.index_id = p.index_id
INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
LEFT OUTER JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.NAME NOT LIKE ''dt%''
AND t.is_ms_shipped = 0
AND i.OBJECT_ID > 255
GROUP BY t.Name, s.Name, p.Rows,t.create_date
ORDER BY total_space_mb DESC, t.Name
END'
INSERT INTO @Tmp_TablesInformation
EXEC sp_MSForEachDB @command
IF @persistData = 'N'
SELECT * FROM @Tmp_TablesInformation
ELSE
BEGIN
IF(@truncateTable = 'Y')
TRUNCATE TABLE DBA_Tables
INSERT INTO DBA_Tables
SELECT *,GETDATE() FROM @Tmp_TablesInformation ORDER BY [database],[schema],[table]
END
END
GO
इस बिंदु तक, जानकारी थोड़ी सूखी लगती है, लेकिन मैं उस धारणा को एक पूरक संग्रहीत प्रक्रिया की प्रस्तुति के साथ बदल देता हूं। इसका मुख्य उद्देश्य लक्ष्य तालिका में एकत्रित जानकारी को स्थानांतरित करना है जो प्रवृत्ति रिपोर्ट के स्रोत के रूप में कार्य करता है।
यहां बताया गया है कि आप संग्रहित प्रक्रिया को कैसे निष्पादित कर सकते हैं:
*प्रदर्शन उद्देश्यों के लिए, मैंने अपने सामान्य संग्रहीत कार्यविधि निष्पादन का अनुकरण करने के लिए t1 नाम की लक्ष्य तालिका में मैन्युअल रिकॉर्ड सम्मिलित किए हैं।
*परिणाम सेट थोड़ा चौड़ा है, इसलिए मैं पूरा आउटपुट दिखाने के लिए कुछ स्क्रीनशॉट लूंगा।
EXEC TransposeTablesInformation @targetParmeter = 'row_count'
मुख्य निष्कर्ष
- यदि आप लक्ष्य तालिका को पॉप्युलेट करने वाली स्क्रिप्ट के निष्पादन को स्वचालित करते हैं, तो आप तुरंत नोटिस कर सकते हैं कि क्या इसमें या आपके डेटा के साथ कुछ गलत हुआ है। तालिका 't1' और कॉलम '15' के डेटा पर एक नज़र डालें। आप वहां NULL देख सकते हैं जो आपको कुछ ऐसा दिखाने के उद्देश्य से किया गया था जो हो सकता है।
- इस तरह के दृष्टिकोण से, आप सबसे महत्वपूर्ण/महत्वपूर्ण डेटाबेस तालिकाओं के लिए एक विशिष्ट व्यवहार देख सकते हैं।
- मैंने दिया गया उदाहरण, मैंने लक्ष्य तालिका के 'row_count' फ़ील्ड को चुना है, लेकिन आप पैरामीटर के रूप में कोई अन्य संख्यात्मक फ़ील्ड चुन सकते हैं और समान तालिका प्रारूप प्राप्त कर सकते हैं, लेकिन विभिन्न डेटा के साथ।
- चिंता न करें, यदि आप एक अमान्य पैरामीटर निर्दिष्ट करते हैं, तो संग्रहीत प्रक्रिया आपको चेतावनी देगी और इसके निष्पादन को रोक देगी।
यहां संग्रहित प्रक्रिया का एक पूरा कोड है जो लक्ष्य तालिका की जानकारी को स्थानांतरित करता है:
*स्क्रिप्ट की शुरुआत में, आप डिफ़ॉल्ट मान देखेंगे जिसे संग्रहीत प्रक्रिया मानती है यदि प्रत्येक पैरामीटर के लिए कोई मान पास नहीं किया जाता है।
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE OR ALTER PROCEDURE [dbo].[TransposeTablesInformation]
@targetParameter NVARCHAR(15) = 'row_count'
AS
BEGIN
SET NOCOUNT ON;
IF (@targetParameter <> 'row_count' AND @targetParameter <> 'total_space_mb' AND @targetParameter <> 'used_space_mb' AND @targetParameter <> 'unused_space_mb')
BEGIN
PRINT 'Please specify a valid parameter!'
PRINT 'i.e. row_count | total_space_mb | used_space_mb | unused_space_mb'
RETURN
END
ELSE
BEGIN
CREATE TABLE #TablesInformation(
[database] [VARCHAR](255) NOT NULL,
[schema] [VARCHAR](64) NOT NULL,
[table] [VARCHAR](255) NOT NULL,
[1] [DECIMAL](10,2) NULL,
[2] [DECIMAL](10,2) NULL,
[3] [DECIMAL](10,2) NULL,
[4] [DECIMAL](10,2) NULL,
[5] [DECIMAL](10,2) NULL,
[6] [DECIMAL](10,2) NULL,
[7] [DECIMAL](10,2) NULL,
[8] [DECIMAL](10,2) NULL,
[9] [DECIMAL](10,2) NULL,
[10] [DECIMAL](10,2) NULL,
[11] [DECIMAL](10,2) NULL,
[12] [DECIMAL](10,2) NULL,
[13] [DECIMAL](10,2) NULL,
[14] [DECIMAL](10,2) NULL,
[15] [DECIMAL](10,2) NULL,
[16] [DECIMAL](10,2) NULL,
[17] [DECIMAL](10,2) NULL,
[18] [DECIMAL](10,2) NULL,
[19] [DECIMAL](10,2) NULL,
[20] [DECIMAL](10,2) NULL,
[21] [DECIMAL](10,2) NULL,
[22] [DECIMAL](10,2) NULL,
[23] [DECIMAL](10,2) NULL,
[24] [DECIMAL](10,2) NULL,
[25] [DECIMAL](10,2) NULL,
[26] [DECIMAL](10,2) NULL,
[27] [DECIMAL](10,2) NULL,
[28] [DECIMAL](10,2) NULL,
[29] [DECIMAL](10,2) NULL,
[30] [DECIMAL](10,2) NULL,
[31] [DECIMAL](10,2) NULL
)
INSERT INTO #TablesInformation([database],[schema],[table])
SELECT DISTINCT [database_name],[schema],[table_name]
FROM DBA_Tables
ORDER BY [database_name],[schema],table_name
DECLARE @databaseName NVARCHAR(255)
DECLARE @schemaName NVARCHAR(64)
DECLARE @tableName NVARCHAR(255)
DECLARE @value DECIMAL(10,2)
DECLARE @dataTimestamp DATETIME
DECLARE @sqlCommand NVARCHAR(MAX)
IF(@targetParameter = 'row_count')
BEGIN
DECLARE TablesCursor CURSOR FOR
SELECT
[database_name],
[schema],
[table_name],
[row_count],
[data_collection_timestamp]
FROM DBA_Tables
ORDER BY [database_name],[schema],table_name
END
IF(@targetParameter = 'total_space_mb')
BEGIN
DECLARE TablesCursor CURSOR FOR
SELECT
[database_name],
[schema],
[table_name],
[total_space_mb],
[data_collection_timestamp]
FROM DBA_Tables
ORDER BY [database_name],[schema],table_name
END
IF(@targetParameter = 'used_space_mb')
BEGIN
DECLARE TablesCursor CURSOR FOR
SELECT
[database_name],
[schema],
[table_name],
[used_space_mb],
[data_collection_timestamp]
FROM DBA_Tables
ORDER BY [database_name],[schema],table_name
END
IF(@targetParameter = 'unused_space_mb')
BEGIN
DECLARE TablesCursor CURSOR FOR
SELECT
[database_name],
[schema],
[table_name],
[unused_space_mb],
[data_collection_timestamp]
FROM DBA_Tables
ORDER BY [database_name],[schema],table_name
END
OPEN TablesCursor
FETCH NEXT FROM TablesCursor INTO @databaseName,@schemaName,@tableName,@value,@dataTimestamp
WHILE(@@FETCH_STATUS = 0)
BEGIN
SET @sqlCommand = CONCAT('
UPDATE #TablesInformation
SET [',DAY(@dataTimestamp),'] = ',@value,'
WHERE [database] = ',CHAR(39),@databaseName,CHAR(39),'
AND [schema] = ',CHAR(39),@schemaName+CHAR(39),'
AND [table] = ',CHAR(39),@tableName+CHAR(39),'
')
EXEC(@sqlCommand)
FETCH NEXT FROM TablesCursor INTO @databaseName,@schemaName,@tableName,@value,@dataTimestamp
END
CLOSE TablesCursor
DEALLOCATE TablesCursor
IF(@targetParameter = 'row_count')
SELECT [database],
[schema],
[table],
CONVERT(INT,[1]) AS [1],
CONVERT(INT,[2]) AS [2],
CONVERT(INT,[3]) AS [3],
CONVERT(INT,[4]) AS [4],
CONVERT(INT,[5]) AS [5],
CONVERT(INT,[6]) AS [6],
CONVERT(INT,[7]) AS [7],
CONVERT(INT,[8]) AS [8],
CONVERT(INT,[9]) AS [9],
CONVERT(INT,[10]) AS [10],
CONVERT(INT,[11]) AS [11],
CONVERT(INT,[12]) AS [12],
CONVERT(INT,[13]) AS [13],
CONVERT(INT,[14]) AS [14],
CONVERT(INT,[15]) AS [15],
CONVERT(INT,[16]) AS [16],
CONVERT(INT,[17]) AS [17],
CONVERT(INT,[18]) AS [18],
CONVERT(INT,[19]) AS [19],
CONVERT(INT,[20]) AS [20],
CONVERT(INT,[21]) AS [21],
CONVERT(INT,[22]) AS [22],
CONVERT(INT,[23]) AS [23],
CONVERT(INT,[24]) AS [24],
CONVERT(INT,[25]) AS [25],
CONVERT(INT,[26]) AS [26],
CONVERT(INT,[27]) AS [27],
CONVERT(INT,[28]) AS [28],
CONVERT(INT,[29]) AS [29],
CONVERT(INT,[30]) AS [30],
CONVERT(INT,[31]) AS [31]
FROM #TablesInformation
ELSE
SELECT * FROM #TablesInformation
END
END
GO
निष्कर्ष
- आप अपने समर्थन के तहत प्रत्येक SQL सर्वर इंस्टेंस में डेटा संग्रह SP को परिनियोजित कर सकते हैं और समर्थित इंस्टेंस के अपने पूरे स्टैक में एक चेतावनी तंत्र लागू कर सकते हैं।
- यदि आप एक एजेंट की नौकरी लागू करते हैं जो इस जानकारी को अपेक्षाकृत बार-बार पूछता है, तो आप यह जानने के मामले में खेल में शीर्ष पर रह सकते हैं कि आपका डेटा महीने के दौरान कैसा व्यवहार करता है। बेशक, आप इससे भी आगे जा सकते हैं और मासिक एकत्र किए गए डेटा को और भी बड़ी तस्वीर के लिए संग्रहीत कर सकते हैं; आपको कोड में कुछ बदलाव करने होंगे, लेकिन यह पूरी तरह से इसके लायक होगा।
- सैंडबॉक्स वातावरण में इस तंत्र का ठीक से परीक्षण करना सुनिश्चित करें और, जब आप उत्पादन परिनियोजन की योजना बना रहे हों, तो कम गतिविधि अवधि चुनना सुनिश्चित करें।
- इस प्रकार की जानकारी एकत्र करने से DBA को एक दूसरे से अलग करने में मदद मिल सकती है। संभवत:3 पक्ष उपकरण हैं जो एक ही काम कर सकते हैं, और इससे भी अधिक, लेकिन सभी के पास इसे वहन करने के लिए बजट नहीं है। मुझे उम्मीद है कि इससे किसी को भी मदद मिल सकती है जो इसे अपने वातावरण में इस्तेमाल करने का फैसला करता है।