डालने के दौरान डिस्क स्पेस फुल, क्या होता है?


17

आज मैंने हार्डड्राइव की खोज की है जो मेरे डेटाबेस को भरता है। ऐसा पहले भी हो चुका है, आमतौर पर इसका कारण काफी स्पष्ट है। आमतौर पर एक खराब क्वेरी होती है, जिससे टेम्पर्ड बी पर भारी फैल होती है जो डिस्क के पूर्ण होने तक बढ़ती रहती है। इस बार यह थोड़ा कम स्पष्ट था कि क्या हुआ, क्योंकि टेम्पर्डब पूर्ण ड्राइव का कारण नहीं था, यह डेटाबेस ही था।

तथ्यों:

  • सामान्य डेटाबेस का आकार लगभग 55 जीबी है, यह बढ़कर 605 जीबी हो गया।
  • लॉग फ़ाइल का आकार सामान्य है, डेटाफ़ाइल विशाल है।
  • Datafile में 85% उपलब्ध स्थान है (मैं इसे 'हवा' के रूप में व्याख्या करता हूं: जिस स्थान का उपयोग किया गया था, लेकिन उसे फ्रीज कर दिया गया है। SQL सर्वर एक बार आवंटित किए गए सभी स्थान को सुरक्षित रखता है)।
  • Tempdb का आकार सामान्य है।

मुझे संभावित कारण मिल गया है; एक क्वेरी है जो बहुत अधिक पंक्तियों का चयन करती है (खराब जुड़ाव 11 बिलियन पंक्तियों के चयन का कारण बनता है जहां एक सौ हजार की उम्मीद है)। यह एक SELECT INTOक्वेरी है, जिसने मुझे आश्चर्यचकित किया है कि क्या निम्न परिदृश्य हो सकता है:

  • Select INTO को अंजाम दिया जाता है
  • लक्ष्य तालिका बनाई गई है
  • डेटा का चयन करते ही डाला जाता है
  • डिस्क भरता है, जिससे इन्सर्ट विफल हो जाता है
  • चयन INTO का गर्भपात किया जाता है और उसे वापस लाया जाता है
  • रोलबैक अंतरिक्ष को मुक्त करता है (पहले से डाला गया डेटा हटा दिया गया है), लेकिन SQL सर्वर मुक्त किए गए स्थान को जारी नहीं करता है।

इस स्थिति में, हालाँकि, मुझे उम्मीद नहीं थी कि तालिका SELECT INTOअभी भी बनी होगी, इसे रोलबैक द्वारा छोड़ दिया जाना चाहिए। मैंने इसका परीक्षण किया:

BEGIN TRANSACTION 
SELECT  T.x
INTO    TMP.test
FROM    (VALUES(1))T(x)

ROLLBACK

SELECT  * 
FROM    TMP.test

इसका परिणाम यह होगा:

(1 row affected)
Msg 208, Level 16, State 1, Line 8
Invalid object name 'TMP.test'.

फिर भी लक्ष्य तालिका मौजूद है। वास्तविक क्वेरी को स्पष्ट लेनदेन में निष्पादित नहीं किया गया था, लेकिन क्या यह लक्ष्य तालिका के अस्तित्व की व्याख्या कर सकता है?

क्या मैंने जो धारणाएँ बनाई हैं, वे यहाँ सही हैं? क्या ऐसा होने की संभावना है?

जवाबों:


17

वास्तविक क्वेरी को स्पष्ट लेनदेन में निष्पादित नहीं किया गया था, लेकिन क्या यह लक्ष्य तालिका के अस्तित्व की व्याख्या कर सकता है?

हाँ, बिलकुल।

यदि आप एक के select intoबाहर एक सरल करते explicit transactionहैं, तो transactionsऑटोोकॉमिट मोड में दो हैं : पहला बनाता है tableऔर दूसरा इसे भरता है।

आप इसे इस तरह से खुद को साबित कर सकते हैं:

में एक databaseपरीक्षण सर्वर पर समर्पित में simple recovery model, पहले एक बनाओ checkpointऔर सुनिश्चित करें कि लॉग में केवल कुछ पंक्तियाँ (2016 के मामले में 3) से संबंधित हैं checkpoint। फिर select intoएक पंक्ति चलाएं और एक logबार फिर से जांच करें कि किससे begin tranसंबंधित है select into:

checkpoint;

select *
from sys.fn_dblog(null, null);

select 'a' as col
into dbo.t3;  

select *
from sys.fn_dblog(null, null)
where Operation = 'LOP_BEGIN_XACT'
      and [Transaction Name] = 'SELECT INTO';

आपको 2 पंक्तियाँ मिलेंगी, जिसमें आपको 2 दिखेंगे transactions

क्या मैंने जो धारणाएँ बनाई हैं, वे यहाँ सही हैं? क्या ऐसा होने की संभावना है?

हाँ, वे सही हैं।

का insertहिस्सा select intoथा rolled back, लेकिन यह कोई डेटा स्पेस जारी नहीं करता है। आप इसे निष्पादित करके सत्यापित कर सकते हैं sp_spaceused; आप बहुत देखेंगे unallocated space

यदि आप चाहते हैं कि डेटाबेस इस अनलॉक्ड स्थान को जारी करे तो आपको shrinkअपनी डेटा फ़ाइल (फाइलें) चाहिए।


15

आप सही हैं, SELECT...INTOकमान परमाणु नहीं है। इसे मूल पोस्ट के समय प्रलेखित नहीं किया गया था, लेकिन अब इसे विशेष रूप से MS डॉक्स (yay ओपन सोर्स!) पर SELECT - INTO क्लॉज (Transact-SQL) पेज पर बुलाया गया है ।

SELECT...INTOबयान दो भागों में चल रही है - नई तालिका बनाई गई है, और उसके बाद पंक्तियों डाला जाता है। इसका मतलब है कि यदि आवेषण विफल हो जाते हैं, तो वे सभी वापस आ जाएंगे, लेकिन नई (खाली) तालिका बनी रहेगी। यदि आपको पूरे ऑपरेशन को सफल होने या एक पूरे के रूप में विफल होने की आवश्यकता है, तो स्पष्ट लेनदेन का उपयोग करें ।

मैं एक डेटाबेस बनाऊंगा जो पूर्ण पुनर्प्राप्ति मॉडल का उपयोग करता है। मैं इसे एक बहुत छोटी लॉग फ़ाइल दूंगा, और फिर उसे बताऊंगा कि लॉग फ़ाइल ऑटोग्रॉव नहीं कर सकती:

CREATE DATABASE [SelectIntoTestDB]
ON PRIMARY 
( 
    NAME = N'SelectIntoTestDB', 
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\SelectIntoTestDB.mdf', 
    SIZE = 8192KB, 
    FILEGROWTH = 65536KB
)
LOG ON 
( 
    NAME = N'SelectIntoTestDB_log', 
    FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL14.SQL2017\MSSQL\DATA\SelectIntoTestDB_log.ldf', 
    SIZE = 8192KB, 
    FILEGROWTH = 0
)

और फिर मैं StackOverflow2010 डेटाबेस की अपनी प्रतिलिपि से सभी पोस्ट सम्मिलित करने का प्रयास करूंगा। यह लॉग फ़ाइल में सामान का एक गुच्छा लिखना चाहिए ।

USE [SelectIntoTestDB];
GO

SELECT *
INTO dbo.Posts
FROM StackOverflow2010.dbo.Posts;

यह 4 सेकंड के लिए चलने के बाद निम्न त्रुटि हुई:

Msg 9002, लेवल 17, स्टेट 4, लाइन 1
डेटाबेस 'SelectIntoTestDB' के लिए लेन-देन लॉग 'ACTIVE_TRANSACTION' के कारण भरा हुआ है।

लेकिन मेरे नए डेटाबेस में एक खाली पोस्ट टेबल है:

नए बनाए गए तालिका से शून्य परिणामों का स्क्रीनशॉट

इसलिए, जैसा कि आपको संदेह था, CREATE TABLEसफल हो गया, लेकिन INSERTभाग सभी वापस लुढ़का हुआ था। वर्कअराउंड एक स्पष्ट लेन-देन का उपयोग करना होगा (जिसे आपने पहले ही अपने प्रश्न में नोट किया था)।

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