अलग SQL सर्वर तालिकाओं में BLOBs को संग्रहीत करने की अनुशंसा क्यों की जाती है?


29

यह अति उत्थानित एसओ उत्तर छवियों को अलग-अलग तालिकाओं में रखने की सलाह देता है, भले ही एक अन्य तालिका के साथ केवल 1: 1 संबंध हो:

यदि आप अपनी तस्वीरों को एक SQL सर्वर तालिका में डालने का निर्णय लेते हैं, तो मैं दृढ़ता से उन चित्रों को संग्रहीत करने के लिए एक अलग तालिका का उपयोग करने की सलाह दूंगा - कर्मचारी तालिका में कर्मचारी की तस्वीर को संग्रहीत न करें - उन्हें एक अलग तालिका में रखें। इस तरह, कर्मचारी तालिका दुबला और मतलबी और बहुत कुशल रह सकती है, यह मानते हुए कि आपको हमेशा अपने प्रश्नों के भाग के रूप में कर्मचारी फोटो का चयन करने की आवश्यकता नहीं है।

क्यूं कर? मैं इस धारणा के तहत था कि SQL सर्वर केवल तालिका में कुछ समर्पित BLOB डेटा संरचना के लिए एक पॉइंटर को संग्रहीत करता है, इसलिए मैन्युअल रूप से अप्रत्यक्ष की एक और परत बनाने के लिए परेशान क्यों हो? क्या यह वास्तव में प्रदर्शन में काफी सुधार करता है? यदि हाँ, तो क्यों?

जवाबों:


15

जबकि मैं असहमत हूं कि बीएलओबी सिर्फ एक और तालिका में होना चाहिए - वे डेटाबेस में बिल्कुल भी नहीं होना चाहिए । एक पॉइंटर को स्टोर करें जहां फ़ाइल डिस्क पर रहती है, और उसके बाद डेटाबेस से प्राप्त करें ...

प्राथमिक मुद्दा वे कारण (मेरे लिए) अनुक्रमण के साथ है। एक्सएमएल का उपयोग क्वेरी प्लान के साथ करें, क्योंकि सभी के पास, आइए एक तालिका बनाएं:

SELECT TOP 1000
ID = IDENTITY(INT,1,1),
deq.query_plan
INTO dbo.index_test
FROM sys.dm_exec_cached_plans AS dec
CROSS APPLY sys.dm_exec_query_plan(dec.plan_handle) AS deq

ALTER TABLE dbo.index_test ADD CONSTRAINT pk_id PRIMARY KEY CLUSTERED (ID)

यह केवल 1000 पंक्तियाँ हैं, लेकिन आकार पर जाँच ...

sp_BlitzIndex @DatabaseName = 'StackOverflow', @SchemaName = 'dbo', @TableName = 'index_test'

यह सिर्फ 1000 पंक्तियों के लिए 40 एमबी से अधिक है। यदि आप हर 1000 पंक्तियों में 40 एमबी जोड़ते हैं, तो यह बहुत जल्दी बदसूरत प्राप्त कर सकता है। जब आप 1 मिलियन पंक्तियों को मारते हैं तो क्या होता है? यह सिर्फ 1 टीबी डेटा है, वहां।

पागल

आपके क्लस्टर्ड इंडेक्स का उपयोग करने के लिए आवश्यक किसी भी क्वेरी को अब उस BLOB डेटा को मेमोरी स्पष्टीकरण में पढ़ने की आवश्यकता है : जब BLOB डेटा कॉलम संदर्भित होता है।

क्या आप BLOB के भंडारण की तुलना में SQL सर्वर मेमोरी का उपयोग करने के बेहतर तरीकों के बारे में सोच सकते हैं? क्योंकि मुझे यकीन है।

इसे गैर-अनुक्रमित अनुक्रमित तक विस्तारित करना:

CREATE INDEX ix_noblob ON dbo.index_test (ID)

CREATE INDEX ix_returnoftheblob ON dbo.index_test (ID) INCLUDE (query_plan)

आप अपने गैर-अनुक्रमित इंडेक्सों को बड़े पैमाने पर BLOB कॉलम से बचने के लिए डिज़ाइन कर सकते हैं, इसलिए नियमित प्रश्न क्लस्टर इंडेक्स से बच सकते हैं, लेकिन जैसे ही आपको BLOB कॉलम की आवश्यकता होती है, आपको क्लस्टर इंडेक्स की आवश्यकता होती है।

यदि आप इसे INCLUDEDकुंजी लुकअप परिदृश्य से बचने के लिए किसी गैर-अनुक्रमित अनुक्रमणिका के स्तंभ के रूप में जोड़ते हैं, तो आप विशाल गैर-अनुक्रमित अनुक्रमणिका के साथ समाप्त होते हैं:यहाँ छवि विवरण दर्ज करें

अधिक समस्याओं के कारण वे:

  • यदि कोई SELECT *क्वेरी चलाता है , तो उन्हें वह सभी BLOB डेटा मिलता है।
  • वे बैकअप और रिस्टोर में जगह लेते हैं, उन्हें धीमा करते हैं
  • वे धीमा कर देते हैं DBCC CHECKDB, क्योंकि मुझे पता है कि आप भ्रष्टाचार की जाँच कर रहे हैं, है ना?
  • और अगर आप कोई इंडेक्स मेंटेन करते हैं, तो वे उसे भी धीमा कर देते हैं।

उम्मीद है की यह मदद करेगा!


7
क्योंकि उपयोगकर्ता आमतौर पर SELECT * टाइप करते हैं।
ब्रेंट ओजर

मुझे लगता है कि आपके द्वारा उल्लिखित डाउनसाइड्स का एक हिस्सा है कि उसने चित्रों को एक अलग तालिका में रखने की सिफारिश क्यों की। यदि मैं उपयोगकर्ताओं पर विभिन्न रिपोर्ट चला रहा हूं, तो मुझे उनकी चित्र फ़ाइल की आवश्यकता नहीं है। यदि मैं किसी एकल उपयोगकर्ता के प्रोफ़ाइल पृष्ठ को लोड कर रहा हूं, तो यह है कि जब मैं ब्लॉब टेबल में शामिल होता हूं, है ना? क्या मुझे यहाँ कुछ याद आ रहा है (यानी आपके डाउनसाइड्स वास्तव में अभी भी इस परिदृश्य में लागू होते हैं जो मैंने वर्णित किया है?)
बीवरन

11

ये चित्र कितने बड़े हैं, और कितने की उम्मीद है? जबकि मैं ज्यादातर @sp_BlitzErik से सहमत हूं , मुझे लगता है कि कुछ परिदृश्य हैं जहां ऐसा करना ठीक है, और इसलिए यह वास्तव में यहां अनुरोध किए जाने के बारे में स्पष्ट चित्र बनाने में मदद करेगा।

यह विचार करने के लिए कि एरिक द्वारा इंगित अधिकांश नकारात्मक पहलुओं को कम करने के लिए कुछ विकल्प हैं:

  • FILESTREAM (SQL Server 2008 में शुरू)
  • FileTables (SQL सर्वर 2012 में शुरू)

इन दोनों विकल्पों को SQL सर्वर में या पूरी तरह से बाहर (पूरी तरह से बाहर रखने के लिए स्ट्रिंग स्ट्रिंग के अलावा) पथ के बीच BLOBs के भंडारण के बीच एक मध्य-भूमि के रूप में डिज़ाइन किया गया है। वे BLOB के लिए डेटा मॉडल का एक हिस्सा होने की अनुमति देते हैं और बफर पूल (यानी मेमोरी) में जगह बर्बाद न करते हुए लेनदेन में भाग लेते हैं। BLOB डेटा को अभी भी बैकअप में शामिल किया गया है, जो उन्हें अधिक स्थान लेने और बैकअप लेने में अधिक समय लेता हैपुन: स्थापित करने हेतु। हालाँकि, मेरे पास इसे देखने के लिए एक कठिन समय है, क्योंकि यह एक वास्तविक नकारात्मक है कि अगर यह ऐप का हिस्सा है, तो इसे किसी भी तरह से बैकअप लेने की आवश्यकता है, और केवल एक स्ट्रिंग कॉलम होने से मार्ग पूरी तरह से डिस्कनेक्ट हो जाता है और BLOBs फ़ाइलों को प्राप्त करने की अनुमति मिलती है डीबी में इसका कोई संकेत नहीं है (यानी अमान्य संकेत / लापता फ़ाइलें)। यह फ़ाइलों को डीबी के भीतर "डिलीट" होने की अनुमति देता है लेकिन अभी भी फाइल सिस्टम पर मौजूद है जिसे अंततः साफ करने की आवश्यकता होगी (यानी सिरदर्द)। लेकिन, अगर फाइलें बहुत बड़ी हैं, तो शायद पथ स्तंभ को छोड़कर SQL सर्वर के बाहर पूरी तरह से छोड़ना सबसे अच्छा है।

यह "अंदर या बाहर" प्रश्न के साथ मदद करता है, लेकिन एकल तालिका बनाम एकाधिक तालिका प्रश्न पर स्पर्श नहीं करता है। मैं कह सकता हूं कि, इस विशिष्ट प्रश्न से परे, निश्चित रूप से उपयोग पैटर्न के आधार पर स्तंभों के समूहों में टेबल को विभाजित करने के लिए वैध मामले हैं। अक्सर जब किसी के पास 50 या अधिक कॉलम होते हैं तो कुछ ऐसे होते हैं जो अक्सर एक्सेस किए जाते हैं और कुछ ऐसे नहीं होते हैं। कुछ कॉलम अक्सर लिखे जाते हैं जबकि कुछ अधिकतर पढ़े जाते हैं। अलग-अलग अक्सर एक्सेस बनाम अलग-अलग एक्सेस किए गए कॉलमों को 1: 1 संबंध में अलग-अलग एक्सेस करना अलग है, क्योंकि यह संभवत: बहुत फायदेमंद होता है क्योंकि क्यों आप संभवतः उपयोग नहीं कर रहे डेटा के लिए बफर पूल में जगह बर्बाद करते हैं (नियमित रूप से बड़ी छवियों को संग्रहीत करने के समान क्योंVARBINARY(MAX)कॉलम एक समस्या है)? आप पंक्ति आकार को कम करके और अक्सर डेटा पेज पर अधिक पंक्तियों को फिट करके, रीड्स (भौतिक और तार्किक दोनों) को अधिक कुशल बनाते हुए, अक्सर एक्सेस कॉलम के प्रदर्शन को बढ़ाते हैं। बेशक, आप PK को डुप्लिकेट करने की आवश्यकता से कुछ अक्षमता का परिचय देते हैं, और अब कभी-कभी आपको दो तालिकाओं में शामिल होने की आवश्यकता होती है, जो कुछ प्रश्नों को भी जटिल करता है (भले ही थोड़ा)।

तो, कई दृष्टिकोण हैं जो आप ले सकते हैं, और जो सबसे अच्छा है वह आपके पर्यावरण पर निर्भर करता है और जिसे आप पूरा करने की कोशिश कर रहे हैं।


मैं इस धारणा के तहत था कि SQL सर्वर केवल तालिका में कुछ समर्पित BLOB डेटा संरचना के लिए एक पॉइंटर को संग्रहीत करता है

इतना आसान नहीं। आप यहाँ कुछ अच्छी जानकारी पा सकते हैं, क्या है (अधिकतम) के लिए लोब पॉइंटर का आकार, जैसे कि वर्चर, वर्बिनरी, आदि? , लेकिन मूल बातें हैं:

  • TEXT, NTEXTऔर IMAGEडेटाटाइप्स (डिफ़ॉल्ट रूप से): 16 बाइट पॉइंटर
  • VARCHAR(MAX), NVARCHAR(MAX), VARBINARY(MAX)(डिफ़ॉल्ट रूप से):
    • यदि डेटा पंक्ति में फिट हो सकता है, तो इसे वहां रखा जाएगा
    • यदि डेटा लगभग अनुमानित से कम है। 40,000 बाइट्स (लिंक्ड ब्लॉग पोस्ट ऊपरी सीमा के रूप में 40,000 दिखाती है लेकिन मेरे परीक्षण ने थोड़ा अधिक मूल्य दिखाया) और अगर इस संरचना के लिए पंक्ति पर जगह है, तो LOB पृष्ठों पर 1 और 5 के बीच सीधा लिंक होगा, जो शुरू हो रहा है पहले बाइट्स के लिए पहले लिंक के लिए 24 बाइट्स, और 8000 बाइट्स के प्रत्येक अतिरिक्त सेट के लिए प्रत्येक अतिरिक्त लिंक पर 12 बाइट्स तक जाने, 72 बाइट्स तक।
    • यदि डेटा लगभग खत्म हो गया है। 40,000 बाइट्स या उचित लिंक की उचित संख्या को स्टोर करने के लिए पर्याप्त जगह नहीं है (उदाहरण के लिए पंक्ति में केवल 40 बाइट्स और 20,000 बाइट मान के लिए 3 लिंक की आवश्यकता होती है जो कि 48 बाइट्स के लिए दो अतिरिक्त लिंक के लिए पहले प्लस 12 के लिए 24 बाइट्स की आवश्यकता होती है) कुल-इन-स्पेस स्थान), फिर एक टेक्स्ट ट्री पेज पर एक 24 बाइट पॉइंटर होगा जिसमें LOB पृष्ठों के लिंक होते हैं)।

7

यदि किसी कारण से डेटा को SQL सर्वर में संग्रहीत किया जाना चाहिए, तो मैं इसे एक अलग तालिका में संग्रहीत करने के कुछ लाभों के बारे में सोच सकता हूं। कुछ दूसरों की तुलना में अधिक आश्वस्त हैं।

  1. डेटा को एक अलग तालिका में रखने का मतलब है कि आप इसे एक अलग डेटाबेस में संग्रहीत कर सकते हैं। यह अनुसूचित रखरखाव के लिए फायदे हो सकते हैं। उदाहरण के लिए, आप DBCC CHECKDBकेवल उस डेटाबेस पर चल सकते हैं जिसमें BLOB डेटा है।

  2. यदि आप हमेशा 8000 से अधिक बाइट्स को BLOB में नहीं डालते हैं, तो कुछ पंक्तियों के लिए इसे पंक्ति में संग्रहीत किया जाना संभव है । आप ऐसा नहीं चाह सकते, क्योंकि यह क्वेरीज़ को धीमा कर देगा, जो क्वेरी द्वारा कॉलम की आवश्यकता नहीं होने पर भी क्लस्टर इंडेक्स का उपयोग करके डेटा तक पहुंच सकता है। एक अलग तालिका में डेटा डालने से यह जोखिम दूर हो जाता है।

  3. जब संग्रहीत पंक्ति SQL सर्वर नए पृष्ठ पर इंगित करने के लिए 24 बाइट पॉइंटर तक का उपयोग करता है। यह स्थान लेता है और आपके द्वारा एकल तालिका में जोड़े जा सकने वाले BLOB स्तंभों की कुल संख्या को सीमित करता है। अधिक विवरण के लिए srutzky का उत्तर देखें।

  4. क्लस्टर किए गए कॉलमस्टोर इंडेक्स को BLOB कॉलम वाली तालिका में परिभाषित नहीं किया जा सकता है। यह सीमा हटा दी गई है SQL Server 2017 में हटा दिया जाएगा।

  5. यदि आप अंततः यह निर्णय लेते हैं कि डेटा को SQL सर्वर से बाहर ले जाना चाहिए, तो यह परिवर्तन करना आसान हो सकता है यदि डेटा पहले से ही एक अलग तालिका में है।


1
यहाँ कुछ अच्छे बिंदु (+1)। लेकिन # 3 (पुनः: 24-बाइट पॉइंटर ऑफ-ऑफ डेटा के लिए) के बारे में स्पष्ट होना, यह हमेशा सही नहीं होता है। मैं अपने जवाब के निचले भाग पर (संक्षेप में) समझाता हूं कि पंक्ति पर डेटाटाइप, मूल्य का आकार और रिक्त स्थान की मात्रा सूचक के आकार को कैसे निर्धारित करती है।
सोलोमन रटज़की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.