2009-07-06 19 views
7

SQL सर्वर (2005+) में मुझे एक कॉलम (केवल सटीक मिलान) इंडेक्स करने की आवश्यकता है जो nvarchar(2000+) है। इस तक पहुंचने का सबसे स्केलेबल, प्रदर्शन करने वाला तरीका क्या है?एसक्यूएल सर्वर इंडेक्स प्रदर्शन - लंबे कॉलम

एसक्यूएल सर्वर में (2005+), क्या व्यावहारिक निम्नलिखित प्रकार के साथ एक स्तंभ पर अनुक्रमण में अंतर होगा:

  • nvarchar(2000)
  • char(40)
  • binary(16)

उदाहरण के लिए अनुक्रमित कॉलम के विरुद्ध एक लुकअप एक अनुक्रमित nvarchar(2000) के विरुद्ध लुकअप से मापने योग्य रूप से तेज़ होगा? यदि हां, तो कितना?

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

+0

आप खोज करने या विशिष्टता को लागू करने की जरूरत है? –

+0

@Alex मुझे विशिष्टता को लागू करने की आवश्यकता है, लेकिन केवल सटीक मिलान कर रहे हैं। –

+0

मैं ट्रिगर्स का उपयोग करूंगा। –

उत्तर

6

आप गलत दिशा से इस बारे में सोच रहे:

  • अनुक्रमित आप प्रदर्शन लक्ष्यों को पूरा करने के लिए अनुक्रमित
  • नहीं बना है की जरूरत बनाने के क्या आप

एक हैं की जरूरत नहीं है कॉलम binary(16) या nvarchar(2000) वहां थोड़ा अंतर बनाता है, क्योंकि आप केवल इंडेक्स को नहीं जोड़ते हैं।

इंडेक्स विकल्प को अपने कॉलम प्रकारों को निर्देशित न करने दें। यदि आपको nvarchar(2000) इंडेक्स करने की आवश्यकता है तो पूर्ण टेक्स्ट इंडेक्स पर विचार करें या कॉलम और इंडेक्स के लिए हैश मान जोड़ना।


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

+0

दरअसल, यह उन कारणों में से एक है जो मैं यह पूछ रहा हूं - क्या एक बड़े क्षेत्र का एक छोटा बाइनरी हैश इंडेक्स के लिए बेहतर होगा? –

+0

एक हैश कॉलम केवल एक सटीक मिलान की तलाश कर सकता है। यदि आपको आंशिक मिलान की आवश्यकता नहीं है (जैसे 'foo%') और न ही श्रेणीएं ('ए' और 'बी' के बीच) तो आप हैंश का उपयोग कर सकते हैं। –

+1

ठीक है: अब हम एक अलग सवाल देख रहे हैं: "मुझे एक nvarchar (2000) कॉलम इंडेक्स करने की आवश्यकता है। लक्ष्य इस प्रकार की क्वेरी को तेजी से चलाने के लिए है: ______। मुझे यह कैसे करना चाहिए?" –

6

पाठक्रम के एक बाइनरी (16) ज्यादा तेजी से हो जाएगा - बस कर गणना की तेज:

  • एक एसक्यूएल सर्वर पृष्ठ हमेशा 8K
  • यदि आप प्रवेश प्रति 16 बाइट्स है, आप 500 प्रविष्टियों एक पेज
  • पर प्रविष्टि प्रति 4000 बाइट (nvarchar) आप प्रति पृष्ठ 2 प्रविष्टियों के साथ खत्म हो जाएगा के साथ (सबसे खराब स्थिति, पूरी तरह से भर अपने nVARCHAR (2000) हैं) स्टोर कर सकते हैं

यदि आपके पास 100'000 प्रविष्टियों वाली तालिका है, तो आपको इंडेक्स के लिए बाइनरी (16) कुंजी के साथ 200 पेज होंगे, जबकि आपको उसी इंडेक्स के लिए 50'000 पृष्ठों की आवश्यकता होगी जिसमें nvarchar (2000)

यहां तक ​​कि हाल ही में जोड़े आई/ओ पढ़ सकते हैं और उन सभी पृष्ठों को स्कैन किसी भी प्रदर्शन आप हो सकता था को मारने के लिए जा रहा है करने के लिए ........

मार्क

अद्यतन:
के लिए मेरी सामान्य अनुक्रमणिका, मैं कंपाउंड इंडेक्स से जितना ज्यादा कर सकता हूं उससे बचने की कोशिश करता हूं - उन्हें अन्य तालिकाओं से संदर्भित करना सिर्फ गन्दा हो जाता है (जहां कई समानता तुलनाओं के साथ खंड होते हैं)।

इसके अलावा, नियमित रूप से अपने सूचकांक की जांच और रखरखाव करें - यदि आपके पास 30% से अधिक विखंडन है, पुनर्निर्माण - यदि आपके पास 5-30% विखंडन है, तो पुनर्गठन करें। एक एसक्यूएल सर्वर मेज पर कुंजी क्लस्टर के लिए एक स्वचालित, अच्छी तरह से परीक्षण किया डीबी सूचकांक रखरखाव http://sqlfool.com/2009/06/index-defrag-script-v30/

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

+0

शुद्ध अंतरिक्ष विचारों के अलावा और क्या? यदि इंडेक्स के साथ कई अन्य कॉलम संग्रहीत किए जाते हैं, तो आपके # पृष्ठ की तुलना काफी कठोर नहीं है, अन्य अंतर क्या होंगे? –

3

आपके पास प्रति इंडेक्स प्रविष्टि में 900 बाइट्स हो सकते हैं, इसलिए आपका nvarchar (2000) उड़ नहीं जाएगा।सबसे बड़ा अंतर इंडेक्स गहराई होगा - जड़ से पत्ते पृष्ठ पर जाने के लिए पृष्ठों की संख्या। इसलिए, यदि आप खोज करने के लिए, आप अंततः पर सूचकांक कर सकते हैं, इस तरह की जरूरत है:,

alter table recipe add text_checksum as checksum(recipe_text) 
create index text_checksum_ind on recipe(text_checksum) 

(यहाँ Indexes on Computed Columns: Speed Up Queries, Add Business Rules से उदाहरण) जो आपको एक सटीक मिलान नहीं देंगे केवल नीचे अपनी खोज को बहुत अच्छी तरह से संकीर्ण।

बेशक

, यदि आप विशिष्टता को लागू करने की जरूरत है, तो आप चलाता का उपयोग करना होगा।

एक और विचार एक छोटे बाइनरी मान, और उस पर अनुक्रमणिका में अपने nvarchar ज़िप करने है, लेकिन आप गारंटी ले सकते हैं कि हर मूल्य हमेशा 900 बाइट या कम करने के लिए ज़िप किया गया है?

+1

+1 उत्कृष्ट बिंदु, हाँ - 900 बाइट्स इंडेक्स प्रविष्टि के लिए अधिकतम है। –

+0

आपको 32 बिट चेकसम की तुलना में बहुत बड़ा हैश की आवश्यकता है। चेक्सम इंट लौटाता है और यह * सर्वोत्तम * मामले में, केवल 64k रिकॉर्ड के बाद 50% संभावना टकराव होगा, एक बहुत ही छोटी तालिका। http://rusanu.com/2009/05/29/lockres-collision-probability-magic-marker-16777215/ –

+0

रीमस, एक बड़े हैश के साथ आपको झूठी सकारात्मक पाने का कम मौका मिलेगा, लेकिन आपके पास अभी भी कुछ होगा। केवल इस मामले में ट्रिगर्स। –

2

In index max length is 900 bytes anyway, तो आप ऐसा नहीं कर सकते सूचकांक NVARCHAR (2000)।

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

अंत में एक प्रश्न में सबसे प्रचलित प्रदर्शन ड्राइविंग मीट्रिक स्कैन किया/की तलाश एड पृष्ठों की संख्या है। यह भौतिक पढ़ने में अनुवाद करता है (= I/O प्रतीक्षा समय) या तार्किक पढ़ता है (= कैश प्रदूषण)।

अंतरिक्ष विचारों के अलावा, डेटा प्रकार क्वेरी व्यवहार में कोई अंतर नहीं करते हैं। char/varchar/nchar/nvarchar में टकराव होते हैं जिन्हें तुलनाओं पर ध्यान में रखा जाना चाहिए, लेकिन कोलेशन ऑर्डर लुकअप की लागत आमतौर पर निर्णायक कारक नहीं होती है।

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

और कभी-कभी आपको समवर्ती मुद्दों पर विचार करना पड़ता है, जैसे कि आपको deadlocks caused by distinct update access path to the same record को खत्म करना होगा।

पोस्ट संपादित

एक मौजूदा MD5 हैश स्तंभ उपयोग के बाद अद्यतन:

create table foo (
    bar nvarchar(2000) not null, 
    [hash] as hashbytes('MD5', bar) persisted not null, 
    constraint pk_hash unique ([hash])); 
go 


insert into foo (bar) values (N'Some text'); 
insert into foo (bar) values (N'Other text'); 
go 

select * from foo 
    where [hash] = hashbytes('MD5', N'Some text'); 
go 

आप बहुत अपने चाहता है के साथ सावधान रहना होगा, हैश इनपुट में कोई अंतर, यानी के लिए बेतहाशा अलग होगा । यदि आप यूनिकोड के बजाय असीसी पैरामीटर चाहते हैं ...

आपकी तालिका decent collision chance होगी यदि आपकी तालिका बड़ी हो जाती है।

0

असल में बेंचमार्क करना और खुद के लिए देखना बेहतर है। उदाहरण के लिए, निम्न स्क्रिप्ट एक इंडेक्स की तुलना करता है जो एक 4 बाइट पूर्णांक बनाम एक 50 बाइट चार के माध्यम से एक खोज के माध्यम से खोजता है। यह एक int (एक आईएनटी कॉलम पर बने बी-पेड़ की गहराई) के लिए 3 पढ़ता है, बनाम चार के लिए पढ़ता है (एक वर्ण स्तंभ पर बने बी-पेड़ की गहराई)।

CREATE TABLE dbo.NarrowKey(n INT NOT NULL PRIMARY KEY, m INT NOT NULL) 
GO 
DECLARE @i INT; 
SET @i = 1; 
INSERT INTO dbo.NarrowKey(n,m) SELECT 1,1; 
WHILE @i<1024000 BEGIN 
    INSERT INTO dbo.NarrowKey(n,m) 
    SELECT n + @i, n + @i FROM dbo.NarrowKey; 
    SET @i = @i * 2; 
END; 
GO 
DROP TABLE dbo.WideKey 
GO 
CREATE TABLE dbo.WideKey(n CHAR(50) NOT NULL PRIMARY KEY, m INT NOT NULL) 
GO 
DECLARE @i INT; 
SET @i = 1; 
INSERT INTO dbo.WideKey(n,m) SELECT '1',1; 
WHILE @i<1024000 BEGIN 
    INSERT INTO dbo.WideKey(n,m) 
    SELECT CAST((m + @i) AS CHAR(50)), n + @i FROM dbo.WideKey; 
    SET @i = @i * 2; 
END; 
GO 
SET STATISTICS IO ON; 
SET STATISTICS TIME ON; 
GO 
SELECT * FROM dbo.NarrowKey WHERE n=123456 
SELECT * FROM dbo.WideKey WHERE n='123456' 

सूचकांक चाहता है एक व्यापक कुंजी के लिए 33% कम होती है लेकिन तालिका 4 बार बड़ा है:

EXEC sp_spaceused 'dbo.NarrowKey'; 
-- 32K 
EXEC sp_spaceused 'dbo.WideKey'; 
-- 136K 
संबंधित मुद्दे