चूँकि कोई varchar
भी स्थान गतिशील रूप से आवंटित करता है, मेरा प्रश्न यह है कि क्या उपयोग varchar(255)
करने की तुलना में अधिक कुशल है या अधिक स्थान बचा है varchar(5000)
। यदि हाँ, तो क्यों?
चूँकि कोई varchar
भी स्थान गतिशील रूप से आवंटित करता है, मेरा प्रश्न यह है कि क्या उपयोग varchar(255)
करने की तुलना में अधिक कुशल है या अधिक स्थान बचा है varchar(5000)
। यदि हाँ, तो क्यों?
जवाबों:
हां, 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 से नीचे कुछ भी?)
rowcount*(column_size/2)
।