SQL सर्वर किसी विदेशी कुंजी संदर्भ के लिए एक इंडेक्स कुंजी कैसे चुनता है?


9

मैं एक विरासत डेटाबेस के साथ काम कर रहा हूं जिसे एमएस एक्सेस से आयात किया गया था। गैर-संकुल, अद्वितीय प्राथमिक कुंजी के साथ लगभग बीस टेबल हैं जो एमएस एक्सेस> SQL सर्वर अपग्रेड के दौरान बनाए गए थे।

इनमें से कई तालिकाओं में अद्वितीय, गैर-संकुल सूचकांक भी हैं जो प्राथमिक कुंजी के डुप्लिकेट हैं।

मैं इसे साफ करने का प्रयास कर रहा हूं।

लेकिन मैंने जो पाया है वह प्राथमिक कुंजी को क्लस्टर इंडेक्स के रूप में फिर से बनाने के बाद है, और फिर विदेशी कुंजी को फिर से बनाने की कोशिश करता हूं, विदेशी कुंजी पुराने, डुप्लिकेट इंडेक्स (जो अद्वितीय थी) को संदर्भित कर रही है।

मुझे यह पता है क्योंकि यह मुझे डुप्लिकेट इंडेक्स को छोड़ने नहीं देगा।

मुझे लगता है कि अगर कोई मौजूद होता है तो SQL सर्वर हमेशा एक प्राथमिक कुंजी का चयन करेगा। SQL सर्वर में एक अद्वितीय सूचकांक और एक प्राथमिक कुंजी के बीच चयन करने की एक विधि है?

समस्या को दूर करने के लिए (SQL Server 2008 R2 पर):

IF EXISTS (SELECT * FROM sys.tables WHERE name = 'Child') DROP TABLE Child
GO
IF EXISTS (SELECT * FROM sys.tables WHERE name = 'Parent') DROP TABLE Parent
GO

-- Create the parent table
CREATE TABLE Parent (ParentID INT NOT NULL IDENTITY(1,1)) 

-- Make the parent table a heap
ALTER TABLE Parent ADD CONSTRAINT PK_Parent PRIMARY KEY NONCLUSTERED (ParentID) 

-- Create the duplicate index on the parent table
CREATE UNIQUE NONCLUSTERED INDEX IX_Parent ON Parent (ParentID) 

-- Create the child table
CREATE TABLE Child  (ChildID  INT NOT NULL IDENTITY(1,1), ParentID INT NOT NULL ) 

-- Give the child table a normal PKey
ALTER TABLE Child ADD CONSTRAINT PK_Child PRIMARY KEY CLUSTERED (ChildID) 

-- Create a foreign key relationship with the Parent table on ParentID
ALTER TABLE Child ADD CONSTRAINT FK_Child FOREIGN KEY (ParentID) 
REFERENCES Parent (ParentID) ON DELETE CASCADE NOT FOR REPLICATION

-- Try to clean this up
-- Drop the foreign key constraint on the Child table
ALTER TABLE Child DROP CONSTRAINT FK_Child

-- Drop the primary key constraint on the Parent table
ALTER TABLE Parent DROP CONSTRAINT PK_Parent

-- Recreate the primary key on Parent as a clustered index
ALTER TABLE Parent ADD CONSTRAINT PK_Parent PRIMARY KEY CLUSTERED (ParentID) 

-- Recreate the foreign key in Child pointing to parent ID
ALTER TABLE Child ADD CONSTRAINT FK_Child FOREIGN KEY (ParentID) 
REFERENCES Parent (ParentID) ON DELETE CASCADE NOT FOR REPLICATION

-- Try to drop the duplicate index on Parent 
DROP INDEX IX_Parent ON Parent 

त्रुटि संदेश:

Msg 3723, स्तर 16, राज्य 6, लाइन 36 एक स्पष्ट DROP INDEX को अनुक्रमणिका 'Parent.IX_Parent' पर अनुमति नहीं है। इसका उपयोग FOREIGN KEY बाधा निवारण के लिए किया जा रहा है।


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
पॉल व्हाइट 9

जवाबों:


7

प्रलेखन की कमी से पता चलता है कि यह व्यवहार एक कार्यान्वयन विवरण है, और इसलिए अपरिभाषित है और किसी भी समय परिवर्तन के अधीन है।

यह CREATE FULLTEXT INDEX के विपरीत है , जहां आपको संलग्न करने के लिए एक इंडेक्स का नाम निर्दिष्ट करना होगा - AFAIK, FOREIGN KEYसमतुल्य करने के लिए कोई अनजाने वाक्यविन्यास नहीं है (हालांकि सैद्धांतिक रूप से, भविष्य में हो सकता है)।

जैसा कि उल्लेख किया गया है, यह समझ में आता है कि SQL सर्वर सबसे छोटे भौतिक सूचकांक को चुनता है जिसके साथ विदेशी कुंजी को जोड़ा जाता है। यदि आप अद्वितीय अवरोध बनाने के लिए स्क्रिप्ट बदलते हैं CLUSTERED, तो स्क्रिप्ट 2008 R2 पर "काम करती है"। लेकिन वह व्यवहार अभी भी अपरिभाषित है और उस पर भरोसा नहीं किया जाना चाहिए।

अधिकांश विरासत अनुप्रयोगों के रूप में, आपको सिर्फ नीटी-किरकिरी और साफ-सुथरी चीजों को प्राप्त करना होगा।


"SQL सर्वर सबसे छोटे भौतिक सूचकांक को चुनता है जिसके साथ विदेशी कुंजी को जोड़ना है" जरूरी नहीं कि वास्तव में। पड़ोसी उत्तर में एक उदाहरण है जहां SqlServer सूचकांक का चयन करता है जो सबसे छोटे भौतिक आकार का नहीं है।
i-एक

3

SQL सर्वर में एक अद्वितीय सूचकांक और एक प्राथमिक कुंजी के बीच चयन करने की एक विधि है?

कम से कम प्राथमिक कुंजी को संदर्भित करने के लिए SqlServer को निर्देशित करना संभव है, जब विदेशी कुंजी बनाई जा रही है और वैकल्पिक कुंजी की कमी या अद्वितीय अनुक्रमित तालिका को संदर्भित किया जा रहा है।

यदि प्राथमिक कुंजी को संदर्भित करने की आवश्यकता है, तो संदर्भित तालिका के केवल नाम को विदेशी कुंजी परिभाषा में निर्दिष्ट किया जाना चाहिए और संदर्भित किए जा रहे स्तंभों की सूची को छोड़ दिया जाना चाहिए:

ALTER TABLE Child
    ADD CONSTRAINT FK_Child_Parent FOREIGN KEY (ParentID)
        -- omit key columns of the referenced table
        REFERENCES Parent /*(ParentID)*/;

अधिक विवरण नीचे।


निम्नलिखित सेटअप पर विचार करें:

CREATE TABLE T (id int NOT NULL, a int, b int, c uniqueidentifier, filler binary(1000));
CREATE TABLE TRef (tid int NULL);

जहाँ तालिका TRefसंदर्भ तालिका के लिए अभिप्रेत है T

संदर्भ संबंधी बाधा पैदा करने के लिए कोई व्यक्ति ALTER TABLEदो विकल्पों के साथ कमांड का उपयोग कर सकता है :

ALTER TABLE TRef
    ADD CONSTRAINT FK_TRef_T_1 FOREIGN KEY (tid) REFERENCES T (id);

ALTER TABLE TRef
    ADD CONSTRAINT FK_TRef_T_2 FOREIGN KEY (tid) REFERENCES T;

ध्यान दें कि दूसरे मामले में संदर्भित की जा रही तालिका के कोई कॉलम निर्दिष्ट नहीं हैं ( REFERENCES Tबनाम REFERENCES T (id))।

चूंकि Tअभी तक कोई प्रमुख सूचकांक नहीं हैं, इसलिए इन आदेशों का निष्पादन त्रुटियों को उत्पन्न करेगा।

पहली कमांड त्रुटि के बाद लौटती है:

सुश्री 1776, स्तर 16, राज्य 0, पंक्ति 4

संदर्भित तालिका 'T' में कोई प्राथमिक या उम्मीदवार कुंजी नहीं हैं जो विदेशी कुंजी 'FK_TRef_T_1' में संदर्भित स्तंभ सूची से मेल खाती हैं।

हालाँकि, दूसरा कमांड अलग त्रुटि देता है:

सुश्री 1773, स्तर 16, राज्य 0, पंक्ति 4

विदेशी कुंजी 'FK_TRef_T_2' में ऑब्जेक्ट 'T' का निहितार्थ होता है, जिस पर प्राथमिक कुंजी परिभाषित नहीं होती है।

देखें कि पहले मामले में उम्मीद प्राथमिक या उम्मीदवार कुंजी है , जबकि दूसरे मामले में उम्मीद केवल प्राथमिक कुंजी है

चलो जांचते हैं कि SqlServer दूसरी कमांड के साथ प्राथमिक कुंजी के अलावा कुछ और का उपयोग करेगा या नहीं।

यदि हम कुछ विशिष्ट अनुक्रमित और अद्वितीय कुंजी जोड़ते हैं T:

CREATE UNIQUE INDEX IX_T_1 on T(id) INCLUDE (filler);
CREATE UNIQUE INDEX IX_T_2 on T(id) INCLUDE (c);
CREATE UNIQUE INDEX IX_T_3 ON T(id) INCLUDE (a, b);

ALTER TABLE T
    ADD CONSTRAINT UQ_T UNIQUE CLUSTERED (id);

FK_TRef_T_1निर्माण के लिए आदेश सफल होता है, लेकिन FK_TRef_T_2सृजन के लिए आदेश अभी भी Msg 1773 के साथ विफल रहता है।

अंत में, यदि हम प्राथमिक कुंजी जोड़ते हैं T:

ALTER TABLE T
    ADD CONSTRAINT PK_T PRIMARY KEY NONCLUSTERED (id);

FK_TRef_T_2निर्माण के लिए आदेश सफल होता है।

आइए देखें कि तालिका की Tविदेशी कुंजियों द्वारा तालिका के किन अनुक्रमों को संदर्भित किया जाता है TRef:

select
    ix.index_id,
    ix.name as index_name,
    ix.type_desc as index_type_desc,
    fk.name as fk_name
from sys.indexes ix
    left join sys.foreign_keys fk on
        fk.referenced_object_id = ix.object_id
        and fk.key_index_id = ix.index_id
        and fk.parent_object_id = object_id('TRef')
where ix.object_id = object_id('T');

यह रिटर्न:

index_id  index_name  index_type_desc   fk_name
--------- ----------- ----------------- ------------
1         UQ_T        CLUSTERED         NULL
2         IX_T_1      NONCLUSTERED      FK_TRef_T_1
3         IX_T_2      NONCLUSTERED      NULL
4         IX_T_3      NONCLUSTERED      NULL
5         PK_T        NONCLUSTERED      FK_TRef_T_2

देखें कि इसके FK_TRef_T_2अनुरूप PK_T

तो, हाँ, REFERENCES Tवाक्यविन्यास विदेशी कुंजी के उपयोग के साथ TRefप्राथमिक कुंजी को मैप किया जाता है T

मैं सीधे SqlServer प्रलेखन में वर्णित ऐसे व्यवहार को खोजने में सक्षम नहीं था, लेकिन समर्पित Msg 1773 से पता चलता है कि यह आकस्मिक नहीं है। इस तरह के कार्यान्वयन से SQL मानक का अनुपालन होता है, नीचे ANSI / ISO 9075-2: 2003 की धारा 11.8 से छोटा अंश है

11 स्कीमा परिभाषा और हेरफेर

11.8 <संदर्भ संबंधी बाधा परिभाषा>

समारोह
एक निर्देशात्मक बाधा निर्दिष्ट करें।

स्वरूप

<referential constraint definition> ::=
    FOREIGN KEY <left paren> <referencing columns> <right paren>
        <references specification>

<references specification> ::=
    REFERENCES <referenced table and columns>
    [ MATCH <match type> ]
    [ <referential triggered action> ]
...

सिंटेक्स नियम
...
3) केस:
...
बी) यदि <संदर्भित तालिका और कॉलम> एक <संदर्भ कॉलम सूची> निर्दिष्ट नहीं करता है, तो संदर्भित तालिका के तालिका विवरणक में एक अद्वितीय बाधा शामिल होगी जो प्राथमिक कुंजी निर्दिष्ट करती है। बता दें कि संदर्भित कॉलम उस विशिष्ट बाधा में अद्वितीय स्तंभों द्वारा पहचाने जाने वाले स्तंभ या स्तंभ हैं और संदर्भित स्तंभ एक ऐसा स्तंभ है। <संदर्भित तालिका और कॉलम> को स्पष्ट रूप से एक <संदर्भ स्तंभ सूची> निर्दिष्ट करना माना जाएगा, जो कि <अद्वितीय स्तंभ सूची> के समान है।
...

Transact-SQL ANSI SQL को सपोर्ट करता है और बढ़ाता है। हालाँकि यह SQL मानक के अनुरूप नहीं है। SQL Server Transact-SQL ISO / IEC 9075-2 स्टैंडर्ड सपोर्ट डॉक्यूमेंट (MS-TSQLISO02 संक्षेप में, यहां देखें ) नाम का एक दस्तावेज है जो Transact-SQL द्वारा प्रदान किए गए समर्थन के स्तर का वर्णन करता है। दस्तावेज़ मानक के लिए एक्सटेंशन और विविधताओं को सूचीबद्ध करता है। उदाहरण के लिए यह दस्तावेज है कि MATCHक्लॉज़ को संदर्भात्मक बाधा परिभाषा में समर्थित नहीं किया गया है। लेकिन मानक के उद्धृत टुकड़े के लिए प्रासंगिक कोई प्रलेखित विविधताएं नहीं हैं। इसलिए, मेरी राय है कि मनाया गया व्यवहार पर्याप्त रूप से प्रलेखित है।

और के उपयोग के साथ REFERENCES T (<reference column list>) वाक्यविन्यास के ऐसा लगता है कि SqlServer तालिका के अनुक्रमित के बीच पहले उपयुक्त गैर-अनुक्रमित सूचकांक का चयन करता है (जिसे कम से कम index_idप्रतीत होता है, प्रश्न के टिप्पणियों में ग्रहण किए गए सबसे छोटे भौतिक आकार के साथ नहीं), या क्लस्टर सूचकांक यदि यह सूट और कोई उपयुक्त गैर-अनुक्रमित सूचकांक नहीं हैं। ऐसा व्यवहार SqlServer 2008 (संस्करण 10.0) के बाद से सुसंगत प्रतीत होता है। यह केवल पाठ्यक्रम का अवलोकन है, इस मामले में कोई गारंटी नहीं है।

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