क्या varchar (5000) की तुलना में varchar (5000) का उपयोग करना बुरा होगा?


28

चूँकि कोई varcharभी स्थान गतिशील रूप से आवंटित करता है, मेरा प्रश्न यह है कि क्या उपयोग varchar(255)करने की तुलना में अधिक कुशल है या अधिक स्थान बचा है varchar(5000)। यदि हाँ, तो क्यों?


क्या आपको 5000 वर्ण चौड़े स्तंभ की आवश्यकता है? अगर ऐसा क्यों? क्या आपके लिए यहां एक varchar (MAX) कॉलम बेहतर होगा?
रिचर्ड एल डावसन

जवाबों:


52

हां, varchar(5000)इससे भी बदतर हो सकता है varchar(255)यदि सभी मान उत्तरार्द्ध में फिट होंगे। कारण यह है कि SQL सर्वर डेटा आकार का अनुमान लगाएगा और बदले में, एक तालिका में स्तंभों के घोषित ( वास्तविक नहीं ) आकार के आधार पर मेमोरी अनुदान प्राप्त करेगा। जब आपके पास varchar(5000)होगा, तो यह मान लिया जाएगा कि हर मूल्य 2,500 वर्ण लंबा है, और उसी के आधार पर आरक्षित मेमोरी।

यहां बुरी आदतों पर मेरी हाल की GroupBy प्रस्तुति से एक डेमो है जो अपने आप को साबित करना आसान बनाता है (कुछ sys.dm_exec_query_statsआउटपुट कॉलम के लिए SQL सर्वर 2016 की आवश्यकता है , लेकिन अभी भी SET STATISTICS TIME ONपूर्व संस्करणों पर अन्य उपकरणों के साथ साबित होना चाहिए ); यह एक ही डेटा के खिलाफ एक ही क्वेरी के लिए बड़ी मेमोरी और लंबे समय तक रनटाइम दिखाता है - केवल अंतर कॉलम के घोषित आकार है:

-- create three tables with different column sizes
CREATE TABLE dbo.t1(a nvarchar(32),   b nvarchar(32),   c nvarchar(32),   d nvarchar(32));
CREATE TABLE dbo.t2(a nvarchar(4000), b nvarchar(4000), c nvarchar(4000), d nvarchar(4000));
CREATE TABLE dbo.t3(a nvarchar(max),  b nvarchar(max),  c nvarchar(max),  d nvarchar(max));
GO -- that's important

-- Method of sample data pop : irrelevant and unimportant.
INSERT dbo.t1(a,b,c,d)
  SELECT TOP (5000) LEFT(name,1), RIGHT(name,1), ABS(column_id/10), ABS(column_id%10)
  FROM sys.all_columns ORDER BY object_id;
GO 100
INSERT dbo.t2(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
INSERT dbo.t3(a,b,c,d) SELECT a,b,c,d FROM dbo.t1;
GO

-- no "primed the cache in advance" tricks
DBCC FREEPROCCACHE WITH NO_INFOMSGS;
DBCC DROPCLEANBUFFERS WITH NO_INFOMSGS;
GO

-- Redundancy in query doesn't matter! Just has to create need for sorts etc.
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t1 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t2 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO
SELECT DISTINCT a,b,c,d, DENSE_RANK() OVER (PARTITION BY b,c ORDER BY d DESC)
FROM dbo.t3 GROUP BY a,b,c,d ORDER BY c,a DESC;
GO

SELECT [table] = N'...' + SUBSTRING(t.[text], CHARINDEX(N'FROM ', t.[text]), 12) + N'...', 
s.last_dop, s.last_elapsed_time, s.last_grant_kb, s.max_ideal_grant_kb
FROM sys.dm_exec_query_stats AS s CROSS APPLY sys.dm_exec_sql_text(s.sql_handle) AS t
WHERE t.[text] LIKE N'%dbo.'+N't[1-3]%' ORDER BY t.[text];

तो, हाँ, अपने कॉलम को सही आकार दें , कृपया।

इसके अलावा, मैंने varchar (32), varchar (255), varchar (5000), varchar (8000), और varchar (मैक्स) के साथ परीक्षणों को फिर से चलाया। इसी तरह के परिणाम ( विस्तार के लिए क्लिक करें ), हालांकि 32 और 255 के बीच और 5,000 और 8,000 के बीच अंतर, नगण्य थे:

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

यहाँ TOP (5000)पूरी तरह से प्रतिलिपि प्रस्तुत करने योग्य परीक्षण के परिवर्तन के साथ एक और परीक्षा है जिसके बारे में मुझे लगातार बुरा महसूस हो रहा था ( विस्तार करने के लिए क्लिक करें ):

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

तो 10,000 पंक्तियों के बजाय 5,000 पंक्तियों के साथ (और sys.all_columns में 5,000+ पंक्तियाँ कम से कम जहाँ तक SQL Server 2008 R2 है), एक अपेक्षाकृत रैखिक प्रगति देखी जाती है - एक ही डेटा के साथ, बड़ा परिभाषित आकार स्तंभ के लिए, अधिक स्मृति और समय के लिए सटीक एक ही क्वेरी को संतुष्ट करने की आवश्यकता होती है (भले ही इसका कोई अर्थ न हो DISTINCT)।


यह वास्तव में आश्चर्यजनक है। के बीच का अंतर होगा varchar(450)और varchar(255)एक ही हो सकता है? (या 4000 से नीचे कुछ भी?)
a_horse_with_no_name

@a_horse_with_no_name मैंने रनटाइम प्रदर्शन के सभी क्रमों का परीक्षण नहीं किया है, लेकिन मेमोरी अनुदान एक रैखिक प्रगति होगी - यह केवल एक कार्य है rowcount*(column_size/2)
हारून बर्ट्रेंड

यह बहुत निराशाजनक है। हालाँकि, मैं SQL सर्वर के आधुनिक संस्करणों से ग्रस्त नहीं हूँ (जब तक कि परिभाषित लंबाई छोटी है तब 8000 या शायद 4000)।
a_horse_with_no_name

1
@a_horse_with_no_name अच्छी तरह से, यह अनुमान लगाना होगा कि डेटा कितना चौड़ा है ताकि वह गोलियां से बच सके। और कैसे अनुमान लगाना चाहिए? यह एक निष्पादन योजना बनाने के लिए एक अग्रदूत के रूप में सभी चर चौड़ाई स्तंभों की औसत / अधिकतम लंबाई निर्धारित करने के लिए पूरी तालिका को स्कैन और पढ़ नहीं सकता है (और यदि ऐसा हो भी सकता है, तो यह केवल एक recompile के दौरान ऐसा करने में सक्षम होगा)।
हारून बर्ट्रेंड

2
ओरेकल औसत पंक्ति की लंबाई, प्रत्येक स्तंभ के लिए न्यूनतम और अधिकतम मान के साथ-साथ हिस्टोग्राम के बारे में आंकड़े रखता है। पोस्टग्रेज बहुत समान आँकड़े रखता है (यह न्यूनतम लेकिन अधिकतम आवृत्तियों को रिकॉर्ड नहीं करता है)। उनमें से किसी के लिए भी प्रदर्शन में nvarchar (150), nvarchar (2000) या varchar (400) के बीच कोई अंतर नहीं है।
a_horse_with_no_name
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.