अनुक्रमित तालिकाओं में सम्मिलित होने पर मुझे न्यूनतम लॉगिंग क्यों नहीं मिल रही है


14

मैं विभिन्न परिदृश्यों में न्यूनतम लॉगिंग आवेषण का परीक्षण कर रहा हूं और मैंने INSERT INTO में जो पढ़ा है उसे TABLOCK और SQL Server 2016 का उपयोग करके एक गैर-संकुल सूचकांक के साथ एक ढेर में चयन करें + कम से कम लॉग इन करना चाहिए, हालांकि मेरे मामले में जब यह हो रहा है। पूर्ण लॉगिंग। मेरा डेटाबेस सरल रिकवरी मॉडल में है और मैं बिना किसी इंडेक्स और टैबलॉक के ढेर पर न्यूनतम लॉग इन आवेषण को सफलतापूर्वक प्राप्त करता हूं।

मैं परीक्षण करने के लिए स्टैक ओवरफ्लो डेटाबेस के पुराने बैकअप का उपयोग कर रहा हूं और निम्न स्कीमा के साथ पोस्ट टेबल की प्रतिकृति बनाई है ...

CREATE TABLE [dbo].[PostsDestination](
    [Id] [int] NOT NULL,
    [AcceptedAnswerId] [int] NULL,
    [AnswerCount] [int] NULL,
    [Body] [nvarchar](max) NOT NULL,
    [ClosedDate] [datetime] NULL,
    [CommentCount] [int] NULL,
    [CommunityOwnedDate] [datetime] NULL,
    [CreationDate] [datetime] NOT NULL,
    [FavoriteCount] [int] NULL,
    [LastActivityDate] [datetime] NOT NULL,
    [LastEditDate] [datetime] NULL,
    [LastEditorDisplayName] [nvarchar](40) NULL,
    [LastEditorUserId] [int] NULL,
    [OwnerUserId] [int] NULL,
    [ParentId] [int] NULL,
    [PostTypeId] [int] NOT NULL,
    [Score] [int] NOT NULL,
    [Tags] [nvarchar](150) NULL,
    [Title] [nvarchar](250) NULL,
    [ViewCount] [int] NOT NULL
)
CREATE NONCLUSTERED INDEX ndx_PostsDestination_Id ON PostsDestination(Id)

मैं तब इस तालिका में पोस्ट तालिका की प्रतिलिपि बनाने का प्रयास करता हूं ...

INSERT INTO PostsDestination WITH(TABLOCK)
SELECT * FROM Posts ORDER BY Id 

Fn_dblog और लॉग फ़ाइल के उपयोग को देखकर मैं देख सकता हूं कि मुझे इससे न्यूनतम लॉगिंग नहीं मिल रही है। मैंने पढ़ा है कि 2016 से पहले के संस्करणों को आवश्यक रूप से अनुक्रमित तालिकाओं में न्यूनतम रूप से लॉग करने के लिए 610 का पता लगाने वाले झंडे की आवश्यकता होती है, मैंने इसे स्थापित करने की भी कोशिश की है लेकिन अभी भी कोई खुशी नहीं है।

मुझे लगता है मैं यहाँ कुछ याद कर रहा हूँ?

EDIT - अधिक जानकारी

अधिक जानकारी जोड़ने के लिए मैं निम्नलिखित प्रक्रिया का उपयोग कर रहा हूं जिसे मैंने न्यूनतम लॉगिंग का पता लगाने के लिए लिखा है, हो सकता है कि मुझे यहां कुछ गलत मिला हो ...

/*
    Example Usage...

    EXEC sp_GetLogUseStats
   @Sql = '
      INSERT INTO PostsDestination
      SELECT TOP 500000 * FROM Posts ORDER BY Id ',
   @Schema = 'dbo',
   @Table = 'PostsDestination',
   @ClearData = 1

*/

CREATE PROCEDURE [dbo].[sp_GetLogUseStats]
(   
   @Sql NVARCHAR(400),
   @Schema NVARCHAR(20),
   @Table NVARCHAR(200),
   @ClearData BIT = 0
)
AS

IF @ClearData = 1
   BEGIN
   TRUNCATE TABLE PostsDestination
   END

/*Checkpoint to clear log (Assuming Simple/Bulk Recovery Model*/
CHECKPOINT  

/*Snapshot of logsize before query*/
CREATE TABLE #BeforeLogUsed(
   [Db] NVARCHAR(100),
   LogSize NVARCHAR(30),
   Used NVARCHAR(50),
   Status INT
)
INSERT INTO #BeforeLogUsed
EXEC('DBCC SQLPERF(logspace)')

/*Run Query*/
EXECUTE sp_executesql @SQL

/*Snapshot of logsize after query*/
CREATE TABLE #AfterLLogUsed(    
   [Db] NVARCHAR(100),
   LogSize NVARCHAR(30),
   Used NVARCHAR(50),
   Status INT
)
INSERT INTO #AfterLLogUsed
EXEC('DBCC SQLPERF(logspace)')

/*Return before and after log size*/
SELECT 
   CAST(#AfterLLogUsed.Used AS DECIMAL(12,4)) - CAST(#BeforeLogUsed.Used AS DECIMAL(12,4)) AS LogSpaceUsersByInsert
FROM 
   #BeforeLogUsed 
   LEFT JOIN #AfterLLogUsed ON #AfterLLogUsed.Db = #BeforeLogUsed.Db
WHERE 
   #BeforeLogUsed.Db = DB_NAME()

/*Get list of affected indexes from insert query*/
SELECT 
   @Schema + '.' + so.name + '.' +  si.name AS IndexName
INTO 
   #IndexNames
FROM 
   sys.indexes si 
   JOIN sys.objects so ON si.[object_id] = so.[object_id]
WHERE 
   si.name IS NOT NULL
   AND so.name = @Table
/*Insert Record For Heap*/
INSERT INTO #IndexNames VALUES(@Schema + '.' + @Table)

/*Get log recrod sizes for heap and/or any indexes*/
SELECT 
   AllocUnitName,
   [operation], 
   AVG([log record length]) AvgLogLength,
   SUM([log record length]) TotalLogLength,
   COUNT(*) Count
INTO #LogBreakdown
FROM 
   fn_dblog(null, null) fn
   INNER JOIN #IndexNames ON #IndexNames.IndexName = allocunitname
GROUP BY 
   [Operation], AllocUnitName
ORDER BY AllocUnitName, operation

SELECT * FROM #LogBreakdown
SELECT AllocUnitName, SUM(TotalLogLength)  TotalLogRecordLength 
FROM #LogBreakdown
GROUP BY AllocUnitName

निम्नलिखित कोड का उपयोग करके कोई अनुक्रमणिका और TABLOCK के साथ ढेर में सम्मिलित करना ...

EXEC sp_GetLogUseStats
   @Sql = '
      INSERT INTO PostsDestination
      SELECT * FROM Posts ORDER BY Id ',
   @Schema = 'dbo',
   @Table = 'PostsDestination',
   @ClearData = 1

मुझे ये परिणाम मिले

यहाँ छवि विवरण दर्ज करें

0.0024mb लॉग फ़ाइल विकास में, बहुत छोटे लॉग रिकॉर्ड आकार और उनमें से बहुत से मुझे खुशी है कि यह न्यूनतम लॉगिंग का उपयोग कर रहा है।

अगर मैं तब आईडी पर एक गैर क्लस्टर सूचकांक बनाता हूँ ...

CREATE INDEX ndx_PostsDestination_Id ON PostsDestination(Id)

तो फिर से मेरी वही प्रविष्टि चलाने ...

यहाँ छवि विवरण दर्ज करें

न केवल मुझे नॉन क्लस्टर्ड इंडेक्स पर न्यूनतम लॉगिंग नहीं मिल रही है, बल्कि मैंने इसे ढेर पर भी खो दिया है। कुछ और परीक्षण करने के बाद ऐसा लगता है कि अगर मैं आईडी क्लस्टर करता हूं तो यह न्यूनतम रूप से लॉग इन करता है, लेकिन मैंने जो पढ़ा है उससे 2016+ को न्यूनतम रूप से गैर-संकुलित सूचकांक के साथ ढेर में लॉग इन करना चाहिए जब टैब्लॉक का उपयोग किया जाता है।

अंतिम संस्करण :

मैंने SQL सर्वर UserVoice पर Microsoft को व्यवहार की सूचना दी है और यदि मुझे कोई प्रतिक्रिया मिलती है तो मैं अपडेट करूंगा। मैंने उन न्यूनतम लॉग परिदृश्यों की पूरी जानकारी भी लिखी है जो मुझे https://gavindraper.com/2018/05/29/SQL-Server-Minimal-Logging-Inserts/ पर काम करने के लिए नहीं मिल सके।


3
पॉल व्हाइट के पास यहां एक उपयोगी संबंधित उत्तर है
एरिक डार्लिंग

जवाबों:


12

मैं SQL सर्वर 2017 पर स्टैक ओवरफ्लो 2010 डेटाबेस का उपयोग करके आपके परिणामों को पुन: प्रस्तुत कर सकता हूं, लेकिन (सभी) आपके निष्कर्ष पर नहीं।

मिनिमल प्रवेश करने के लिए ढेर अनुपलब्ध उपयोग कर रहा है INSERT...SELECTके साथ TABLOCKnonclustered अनुक्रमणिका है, जो है के साथ एक ढेर करने के लिए अप्रत्याशित । मेरा अनुमान एक ही समय में (ढेर) INSERT...SELECTका उपयोग करके बल्क भार का समर्थन नहीं कर सकता हैRowsetBulkFastLoadContext (बी-ट्री) के ( । केवल Microsoft ही यह पुष्टि कर पाएगा कि यह बग है या डिज़ाइन द्वारा।

Nonclustered अनुक्रमणिका ढेर पर न्यूनतम लॉग होता है (यह मानते हुए TF610 पर है, या SQL सर्वर 2016+ प्रयोग किया जाता है, को सक्षम करने FastLoadContext) निम्न चेतावनियां साथ:

  • केवल नए आबंटित पृष्ठों में डाली गई पंक्तियाँ न्यूनतम रूप से लॉग इन हैं।
  • पहले अनुक्रमणिका पृष्ठ पर जोड़े गए पंक्तियों को न्यूनतम रूप से लॉग नहीं किया गया है, यदि ऑपरेशन की शुरुआत में सूचकांक खाली था।

LOP_INSERT_ROWSगैर-अनुक्रमित अनुक्रमणिका के लिए दिखाई गई 497 प्रविष्टियाँ, सूचकांक के पहले पृष्ठ के अनुरूप हैं। चूंकि सूचकांक पहले से खाली था, इसलिए ये पंक्तियाँ पूरी तरह से लॉग इन हैं। शेष पंक्तियाँ सभी न्यूनतम रूप से लॉग इन हैं । यदि दस्तावेज़ ट्रेस ध्वज 692 अक्षम करने के लिए सक्षम किया गया है (2016+) FastLoadContext, तो सभी गैर- अनुक्रमित अनुक्रमणिका पंक्तियाँ न्यूनतम रूप से लॉग इन हैं।


मैंने पाया कि न्यूनतम लॉगिंग को ढेर और गैर-अनुक्रमित दोनों सूचकांक पर लागू किया जाता है जब BULK INSERTएक फ़ाइल से एक ही तालिका (इंडेक्स के साथ) का उपयोग करते हुए थोक लोड हो रहा है:

BULK INSERT dbo.PostsDestination
FROM 'D:\SQL Server\Posts.bcp'
WITH (TABLOCK, DATAFILETYPE = 'native');

मैं इसे पूर्णता के लिए नोट करता हूं। बल्क लोडिंग INSERT...SELECTविभिन्न कोड रास्तों का उपयोग करता है, इसलिए तथ्य भिन्न व्यवहार पूरी तरह से अप्रत्याशित नहीं है।


SQLPerformance.com पर मेरी तीन भाग श्रृंखला देखने और उपयोग करने के साथ न्यूनतम लॉगिंग के बारे में पूरी जानकारी के लिए :RowsetBulkFastLoadContextINSERT...SELECT

  1. INSERT के साथ न्यूनतम लॉगिंग… हीप टेबल्स में चयन करें
  2. INSERT के साथ न्यूनतम लॉगिंग ... रिक्त क्लस्टर में तालिकाओं का चयन करें
  3. INSERT के साथ न्यूनतम लॉगिंग ... चयन और फास्ट लोड संदर्भ

आपके ब्लॉग पोस्ट से अन्य परिदृश्य

टिप्पणियाँ बंद हो जाती हैं इसलिए मैं यहां संक्षेप में संबोधित करूंगा।

ट्रेस 610 या 2016+ के साथ खाली क्लस्टर सूचकांक

यह FastLoadContextबिना उपयोग किए न्यूनतम रूप से लॉग इन है TABLOCK। पूरी तरह से लॉग की गई एकमात्र पंक्तियों को पहले पृष्ठ पर डाला गया है क्योंकि लेनदेन की शुरुआत में क्लस्टर इंडेक्स खाली था।

डेटा और ट्रेस 610 या 2016+ के साथ क्लस्टर इंडेक्स

यह भी न्यूनतम लॉग इन का उपयोग कर रहा है FastLoadContext । मौजूदा पृष्ठ पर जोड़े गए पंक्तियों को पूरी तरह से लॉग किया गया है, शेष न्यूनतम लॉग किए गए हैं।

गैर-संकुलित सूचकांक और टैब लॉक या ट्रेस 610 / एसक्यूएल 2016+ के साथ क्लस्टर इंडेक्स

यह भी न्यूनतम लॉग इन किया जा सकता है FastLoadContextजब तक कि गैर-अनुक्रमित सूचकांक एक अलग ऑपरेटर द्वारा बनाए रखा जाता है, DMLRequestSortसही पर सेट होता है, और मेरी पोस्ट में रखी गई अन्य शर्तें पूरी होती हैं।


2

नीचे दिया गया दस्तावेज़ पुराना है लेकिन फिर भी एक उत्कृष्ट पढ़ा गया है।

SQL 2016 ट्रेस ध्वज में 610 और ALLOW_PAGE_LOCKS डिफ़ॉल्ट रूप से हैं, लेकिन किसी ने उन्हें अक्षम किया हो सकता है।

डेटा लोड प्रदर्शन गाइड

(3) ऑप्टिमाइज़र द्वारा चुनी गई योजना के आधार पर, तालिका पर गैर-अनुक्रमित सूचकांक या तो पूरी तरह से हो सकता है या न्यूनतम रूप से लॉग इन हो सकता है।

SELECT स्टेटमेंट समस्या हो सकती है क्योंकि आपको एक TOP और ORDER BY मिला है। आप सूचकांक में एक अलग क्रम में तालिका में डेटा सम्मिलित कर रहे हैं, इसलिए SQL पृष्ठभूमि में बहुत कुछ सॉर्टिंग कर सकता है।

अद्यतन २

आप वास्तव में न्यूनतम लॉगिंग प्राप्त कर सकते हैं। TraceFlag 610 ON के साथ, लॉग अलग तरीके से व्यवहार करता है, SQL रोल में बैक करने के लिए लॉग में पर्याप्त स्थान आरक्षित करेगा यदि चीजें गलत हो जाती हैं, लेकिन वास्तव में लॉग का उपयोग नहीं करेगा।

यह शायद आरक्षित (अप्रयुक्त) स्थान की गिनती कर रहा है

EXEC('DBCC SQLPERF(logspace)')

यह कोड प्रयुक्त से आरक्षित को विभाजित करता है

SELECT
    database_transaction_log_bytes_used
    ,database_transaction_log_bytes_reserved
    ,*
FROM sys.dm_tran_database_transactions 
WHERE database_id = DB_ID()

मुझे लगता है कि मिनिमल लॉगिंग (जहां तक ​​माइक्रोसॉफ्ट का संबंध है) वास्तव में लॉग पर कम से कम आईओ का प्रदर्शन करने के बारे में है, न कि यह कि लॉग कितना आरक्षित है।

इस लिंक पर एक नज़र डालें ।

अद्यतन १

TABLOCK के बजाय TABLOCKX का उपयोग करने का प्रयास करें। टैब्लॉक के साथ आपके पास अभी भी एक साझा लॉक है, इसलिए SQL किसी अन्य प्रक्रिया को बंद करने की स्थिति में लॉगिंग कर सकता है।

TABLOCK को HOLDLOCK के साथ संयोजन में उपयोग करने की आवश्यकता हो सकती है। यह आपके लेनदेन के अंत तक टैब्लॉक को लागू करता है।

स्रोत तालिका [डाक] पर भी ताला लगाएं, लॉगिंग हो सकती है क्योंकि स्रोत तालिका बदल सकती है जबकि आपका लेनदेन हो रहा है। पॉल व्हाइट ने न्यूनतम लॉगिंग हासिल की जब स्रोत एसक्यूएल टेबल नहीं था।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.