इस गलत धारणा का कारण संभवतः इस विश्वास के कारण है कि यह सभी कॉलमों को पढ़कर समाप्त हो जाएगा। यह देखना आसान है कि यह मामला नहीं है।
CREATE TABLE T
(
X INT PRIMARY KEY,
Y INT,
Z CHAR(8000)
)
CREATE NONCLUSTERED INDEX NarrowIndex ON T(Y)
IF EXISTS (SELECT * FROM T)
PRINT 'Y'
योजना देता है

इससे पता चलता है कि SQL सर्वर इस तथ्य के बावजूद परिणाम को जांचने के लिए उपलब्ध सबसे संकीर्ण सूचकांक का उपयोग करने में सक्षम था कि सूचकांक में सभी कॉलम शामिल नहीं हैं। इंडेक्स एक्सेस एक सेमी जॉइन ऑपरेटर के तहत है, जिसका अर्थ है कि पहली पंक्ति में वापस आते ही यह स्कैन करना बंद कर सकता है।
तो यह स्पष्ट है कि उपरोक्त धारणा गलत है।
हालांकि क्वेरी ऑप्टिमाइज़र टीम के कॉनर कनिंघम ने यहां बताया कि वह SELECT 1इस मामले में आमतौर पर उपयोग करते हैं क्योंकि यह क्वेरी के संकलन में मामूली प्रदर्शन अंतर ला सकता है।
QP सभी का विस्तार और विस्तार करेगा * पाइपलाइन में का आरंभिक उन्हें वस्तुओं में बाँध देगा (इस मामले में, स्तंभों की सूची)। यह क्वेरी की प्रकृति के कारण अनावश्यक कॉलम हटा देगा।
तो EXISTSइस तरह एक सरल उपश्रेणी के लिए :
SELECT col1 FROM MyTable WHERE EXISTS
(SELECT * FROM Table2 WHERE
MyTable.col1=Table2.col2)*कुछ संभावित बड़ा स्तंभ सूची में विस्तार किया जाएगा और फिर इसे निर्धारित किया जाएगा कि के शब्दों
EXISTS उन स्तंभों में से किसी की आवश्यकता नहीं है, तो मूल रूप से उन सभी हटाया जा सकता है।
" SELECT 1" क्वेरी संकलन के दौरान उस तालिका के लिए किसी भी अनावश्यक मेटाडेटा की जांच करने से बचना होगा।
हालाँकि, रनटाइम के दौरान क्वेरी के दो रूप समान होंगे और इसमें समान रनटाइम होंगे।
मैंने विभिन्न स्तंभों के साथ एक खाली टेबल पर इस क्वेरी को व्यक्त करने के चार संभावित तरीकों का परीक्षण किया। SELECT 1बनाम SELECT *बनाम SELECT Primary_Keyबनाम SELECT Other_Not_Null_Column।
मैंने प्रश्नों को एक लूप में इस्तेमाल किया OPTION (RECOMPILE)और प्रति सेकंड निष्पादन की औसत संख्या को मापा। नीचे परिणाम

+-------------+----------+---------+---------+--------------+
| Num of Cols | * | 1 | PK | Not Null col |
+-------------+----------+---------+---------+--------------+
| 2 | 2043.5 | 2043.25 | 2073.5 | 2067.5 |
| 4 | 2038.75 | 2041.25 | 2067.5 | 2067.5 |
| 8 | 2015.75 | 2017 | 2059.75 | 2059 |
| 16 | 2005.75 | 2005.25 | 2025.25 | 2035.75 |
| 32 | 1963.25 | 1967.25 | 2001.25 | 1992.75 |
| 64 | 1903 | 1904 | 1936.25 | 1939.75 |
| 128 | 1778.75 | 1779.75 | 1799 | 1806.75 |
| 256 | 1530.75 | 1526.5 | 1542.75 | 1541.25 |
| 512 | 1195 | 1189.75 | 1203.75 | 1198.5 |
| 1024 | 694.75 | 697 | 699 | 699.25 |
+-------------+----------+---------+---------+--------------+
| Total | 17169.25 | 17171 | 17408 | 17408 |
+-------------+----------+---------+---------+--------------+
के रूप में देखा जा सकता है के बीच कोई सुसंगत विजेता है SELECT 1और SELECT *और दोनों के बीच अंतर दृष्टिकोण नगण्य है। SELECT Not Null colऔर SELECT PKथोड़ा तेज हालांकि दिखाई देते हैं।
तालिका में स्तंभों की संख्या बढ़ने पर सभी चार प्रश्न प्रदर्शन में कम हो जाते हैं।
तालिका खाली होने के कारण यह संबंध केवल कॉलम मेटाडेटा की मात्रा से ही पता चलता है। के लिए COUNT(1)यह देखने के लिए कि यह फिर से लिखा जाता है आसान है COUNT(*)के नीचे से इस प्रक्रिया में कुछ बिंदु पर।
SET SHOWPLAN_TEXT ON;
GO
SELECT COUNT(1)
FROM master..spt_values
जो निम्न योजना देता है
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1004],0)))
|--Stream Aggregate(DEFINE:([Expr1004]=Count(*)))
|--Index Scan(OBJECT:([master].[dbo].[spt_values].[ix2_spt_values_nu_nc]))
SQL सर्वर प्रक्रिया के लिए डिबगर संलग्न करना और बेतरतीब ढंग से नीचे निष्पादित करते हुए तोड़ना
DECLARE @V int
WHILE (1=1)
SELECT @V=1 WHERE EXISTS (SELECT 1 FROM ##T) OPTION(RECOMPILE)
मैंने पाया कि उन मामलों में जहां टेबल में 1,024 कॉलम होते हैं, ज्यादातर समय कॉल स्टैक नीचे की तरह दिखता है, यह दर्शाता है कि यह वास्तव SELECT 1में उपयोग किए जाने पर भी कॉलम लोड मेटाडेटा का एक बड़ा हिस्सा खर्च कर रहा है (मामले के लिए जहां तालिका में 1 कॉलम बेतरतीब ढंग से टूट रहा है 10 प्रयासों में कॉल स्टैक के इस बिट को हिट नहीं किया है)
sqlservr.exe!CMEDAccess::GetProxyBaseIntnl() - 0x1e2c79 bytes
sqlservr.exe!CMEDProxyRelation::GetColumn() + 0x57 bytes
sqlservr.exe!CAlgTableMetadata::LoadColumns() + 0x256 bytes
sqlservr.exe!CAlgTableMetadata::Bind() + 0x15c bytes
sqlservr.exe!CRelOp_Get::BindTree() + 0x98 bytes
sqlservr.exe!COptExpr::BindTree() + 0x58 bytes
sqlservr.exe!CRelOp_FromList::BindTree() + 0x5c bytes
sqlservr.exe!COptExpr::BindTree() + 0x58 bytes
sqlservr.exe!CRelOp_QuerySpec::BindTree() + 0xbe bytes
sqlservr.exe!COptExpr::BindTree() + 0x58 bytes
sqlservr.exe!CScaOp_Exists::BindScalarTree() + 0x72 bytes
... Lines omitted ...
msvcr80.dll!_threadstartex(void * ptd=0x0031d888) Line 326 + 0x5 bytes C
kernel32.dll!_BaseThreadStart@8() + 0x37 bytes
यह मैनुअल प्रोफाइलिंग प्रयास VS 2012 कोड प्रोफाइलर द्वारा समर्थित है, जो दो मामलों के लिए संकलन समय का उपभोग करने वाले कार्यों का एक बहुत अलग चयन दिखाता है ( शीर्ष 15 कार्य 1024 स्तंभ बनाम शीर्ष 15 कार्य 1 स्तंभ )।
दोनों SELECT 1और SELECT *संस्करण स्तंभ अनुमतियों की जाँच करते हैं और विफल हो जाते हैं यदि उपयोगकर्ता को तालिका के सभी स्तंभों तक पहुँच प्रदान नहीं की जाती है।
एक उदाहरण मैं ढेर पर एक बातचीत से घबरा गया
CREATE USER blat WITHOUT LOGIN;
GO
CREATE TABLE dbo.T
(
X INT PRIMARY KEY,
Y INT,
Z CHAR(8000)
)
GO
GRANT SELECT ON dbo.T TO blat;
DENY SELECT ON dbo.T(Z) TO blat;
GO
EXECUTE AS USER = 'blat';
GO
SELECT 1
WHERE EXISTS (SELECT 1
FROM T);
/* ↑↑↑↑
Fails unexpectedly with
The SELECT permission was denied on the column 'Z' of the
object 'T', database 'tempdb', schema 'dbo'.*/
GO
REVERT;
DROP USER blat
DROP TABLE T
तो कोई अनुमान लगा सकता है कि उपयोग करते समय मामूली स्पष्ट अंतर SELECT some_not_null_col यह है कि यह केवल उस विशिष्ट कॉलम पर जांच की अनुमति देता है (हालांकि अभी भी सभी के लिए मेटाडेटा लोड करता है)। हालांकि यह तथ्यों के साथ फिट नहीं लगता है क्योंकि दोनों दृष्टिकोणों के बीच प्रतिशत अंतर यदि कुछ भी छोटा हो जाता है तो अंतर्निहित तालिका में स्तंभों की संख्या बढ़ जाती है।
किसी भी सूरत में मैं इस फॉर्म में अपने सभी प्रश्नों को जल्दी से जल्दी नहीं बदलूंगा और क्योंकि यह अंतर बहुत ही मामूली है और केवल क्वेरी संकलन के दौरान स्पष्ट है। इसे हटा देना OPTION (RECOMPILE)ताकि बाद के निष्पादन एक कैश्ड योजना का उपयोग कर सकें, निम्नलिखित दिए गए हैं।

+-------------+-----------+------------+-----------+--------------+
| Num of Cols | * | 1 | PK | Not Null col |
+-------------+-----------+------------+-----------+--------------+
| 2 | 144933.25 | 145292 | 146029.25 | 143973.5 |
| 4 | 146084 | 146633.5 | 146018.75 | 146581.25 |
| 8 | 143145.25 | 144393.25 | 145723.5 | 144790.25 |
| 16 | 145191.75 | 145174 | 144755.5 | 146666.75 |
| 32 | 144624 | 145483.75 | 143531 | 145366.25 |
| 64 | 145459.25 | 146175.75 | 147174.25 | 146622.5 |
| 128 | 145625.75 | 143823.25 | 144132 | 144739.25 |
| 256 | 145380.75 | 147224 | 146203.25 | 147078.75 |
| 512 | 146045 | 145609.25 | 145149.25 | 144335.5 |
| 1024 | 148280 | 148076 | 145593.25 | 146534.75 |
+-------------+-----------+------------+-----------+--------------+
| Total | 1454769 | 1457884.75 | 1454310 | 1456688.75 |
+-------------+-----------+------------+-----------+--------------+
मेरे द्वारा उपयोग की जाने वाली परीक्षण स्क्रिप्ट यहां पाई जा सकती है