2013-09-04 6 views
7

मैंने कुछ समय-समय पर कुछ डेटाबेस इंजनों में एसक्यूएल का उपयोग किया है लेकिन थोड़ा सैद्धांतिक ज्ञान है इसलिए मेरा प्रश्न आप में से कुछ के लिए बहुत "नोबिश" हो सकता है। लेकिन अब मेरे लिए यह महत्वपूर्ण हो गया है इसलिए मुझे पूछना है।आदेश और ROW_NUMBER() निर्धारक है?

गैर अद्वितीय कॉलम status के साथ तालिका यूआरएल की कल्पना करें। और सवाल के लिए मान लें कि हमारे पास प्रत्येक रिकॉर्ड में बड़ी मात्रा में पंक्तियां और स्थिति समान मूल्य है।

और कल्पना हम कई बार क्वेरी निष्पादित करें:

SELECT * FROM Urls ORDER BY status 
  1. क्या हम हर बार एक ही पंक्ति के आदेश या नहीं मिल सकता है? अगर हम कुछ नई पंक्तियां जोड़ते हैं तो हम क्या करेंगे? क्या यह ऑर्डर बदलता है या नए रिकॉर्ड परिणामों के अंत में जोड़ा जाएगा? और अगर हमें एक ही आदेश नहीं मिलता है - किस स्थितियों पर इस आदेश पर निर्भर करता है?

  2. क्या ROW_NUMBER() OVER (ORDER BY status) उपरोक्त प्रश्न के रूप में एक ही आदेश वापस करेगा या यह विभिन्न आदेश तंत्र पर आधारित है?

+4

1. संख्या 2. तंत्र एक जैसा है, लेकिन परिणाम अलग हो सकता है। अनियंत्रित पंक्तियों का वास्तविक वापसी आदेश क्वेरी अनुकूलक निर्णयों पर निर्भर करता है और डेटा/इंडेक्स भौतिक लेआउट। – Arvo

उत्तर

9

यह बहुत आसान है। यदि आप एक ऑर्डर करना चाहते हैं जिस पर आप भरोसा कर सकते हैं, तो आपको अपने ORDER BY खंड में पर्याप्त कॉलम शामिल करने की आवश्यकता है जैसे कि उन सभी स्तंभों का संयोजन प्रत्येक पंक्ति के लिए अद्वितीय है। और कुछ भी गारंटी नहीं है।

एक ही तालिका के लिए, आप आम तौर पर प्राथमिक कुंजी कॉलम सहित क्रमबद्ध करने के लिए "दिलचस्प" कॉलम सूचीबद्ध करके कॉलम सूचीबद्ध करके जो चाहते हैं उसे प्राप्त कर सकते हैं। चूंकि पीके, स्वयं ही, विशिष्टता की गारंटी देता है, इसलिए पूरे संयोजन को ऑर्डरिंग को विशिष्ट रूप से परिभाषित करने की भी गारंटी दी जाती है, उदा। Urls तालिका {Site, Page, Ordinal} के एक प्राथमिक कुंजी है, तो निम्नलिखित आप एक भरोसेमंद परिणाम देना होगा:

SELECT * FROM Urls ORDER BY status, Site, Page, Ordinal 
+0

+1 स्पष्ट रूप से यदि आपके पास जॉइन है आपको सभी तालिकाओं के पीके को गठबंधन करना होगा, और यदि आपके पास यूनियन हैं तो आप प्रत्येक यूनियन के लिए मान 1, 2, 3 के साथ एक नया फ़ील्ड जोड़ सकते हैं। – xanatos

7

ORDER BY एसक्यूएल सर्वर में स्थिर नहीं है (और न ही किसी अन्य डेटाबेस में, के रूप में तक मुझे पता है)। एक स्थिर प्रकार वह होता है जो उसी क्रम में रिकॉर्ड देता है जो वे तालिका में पाए जाते हैं।

उच्च स्तरीय कारण काफी सरल है। टेबल्स सेट हैं। उनके पास कोई आदेश नहीं है। तो एक "स्थिर" प्रकार सिर्फ समझ में नहीं आता है।

निचले स्तर के कारण शायद अधिक महत्वपूर्ण हैं। डेटाबेस समानांतर प्रकार एल्गोरिदम लागू कर सकता है। इस तरह के एल्गोरिदम डिफ़ॉल्ट रूप से स्थिर नहीं हैं।

यदि आप एक स्थिर प्रकार चाहते हैं, तो सॉर्टिंग में एक प्रमुख कॉलम शामिल करें।

यह documentation में alluded है:

क्वेरी अनुरोधों के बीच स्थिर परिणाम प्राप्त करने के OFFSET का उपयोग और लाओ, निम्न शर्तें पूरी होनी चाहिए:

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

क्लॉज द्वारा ऑर्डर में कॉलम या संयोजन कॉलम हैं जो अद्वितीय होने की गारंटी है।

+0

मैं लगभग 20 वर्षों के लिए एसक्यूएल का उपयोग कर रहा हूं और एक स्थिर प्रकार की परिभाषा को देखना था। यह भ्रमित है। डेटाबेस के बारे में बात करते समय, आप पहले एसीआईडी ​​सोचते हैं। इसलिए, सबकुछ सुसंगत (स्थिर) होना चाहिए। इस संदर्भ में, आप कह रहे हैं कि पृष्ठों पर डेटा परिणाम के समान क्रम में है (यानी - स्थिर प्रकार)। इसका मतलब यह नहीं है कि सही इस्लामी स्तर के साथ ऑर्डर सही परिणाम नहीं लौटाएगा। –

+0

मैं उलझन में हूँ; सवाल "निर्धारिती" के बारे में पूछता है, यह प्रश्न "स्थिर" के बारे में जवाब देता है; क्या वे [दो अलग-अलग चीजें नहीं हैं?] (http://stackoverflow.com/questions/2313940/what-is-a-deterministic-quicksort#comment2282232_2314031) –

0

मुझे वास्तव में इन प्रकार के प्रश्न पसंद हैं क्योंकि आप प्रदर्शन विश्लेषण कर सकते हैं।

सबसे पहले, एक [यूआरएल] तालिका के साथ एक लाख यादृच्छिक रिकॉर्ड के साथ एक नमूना [परीक्षण] डेटाबेस बनाते हैं।

नीचे कोड देखें।

-- Switch databases 
USE [master]; 
go 

-- Create simple database 
CREATE DATABASE [test]; 
go 

-- Switch databases 
USE [test]; 
go 

-- Create simple table 
CREATE TABLE [urls] 
    (
     my_id INT IDENTITY(1, 1) 
       PRIMARY KEY , 
     my_link VARCHAR(255) , 
     my_status VARCHAR(15) 
    ); 
go 

-- http://stackoverflow.com/questions/1393951/what-is-the-best-way-to-create-and-populate-a-numbers-table 

-- Load table with 1M rows of data 
; 
WITH PASS0 
      AS (SELECT 1 AS C 
       UNION ALL 
       SELECT 1 
      ),   --2 rows 
     PASS1 
      AS (SELECT 1 AS C 
       FROM  PASS0 AS A , 
         PASS0 AS B 
      ), --4 rows 
     PASS2 
      AS (SELECT 1 AS C 
       FROM  PASS1 AS A , 
         PASS1 AS B 
      ), --16 rows 
     PASS3 
      AS (SELECT 1 AS C 
       FROM  PASS2 AS A , 
         PASS2 AS B 
      ), --256 rows 
     PASS4 
      AS (SELECT 1 AS C 
       FROM  PASS3 AS A , 
         PASS3 AS B 
      ), --65536 rows 
     PASS5 
      AS (SELECT 1 AS C 
       FROM  PASS4 AS A , 
         PASS4 AS B 
      ), --4,294,967,296 rows 
     TALLY 
      AS (SELECT ROW_NUMBER() OVER (ORDER BY C) AS Number 
       FROM  PASS5 
      ) 
    INSERT INTO urls 
      (my_link , 
       my_status 
      ) 
      SELECT 
     -- top 10 search engines + me 
        CASE (Number % 11) 
         WHEN 0 THEN 'www.ask.com' 
         WHEN 1 THEN 'www.bing.com' 
         WHEN 2 THEN 'www.duckduckgo.com' 
         WHEN 3 THEN 'www.dogpile.com' 
         WHEN 4 THEN 'www.webopedia.com' 
         WHEN 5 THEN 'www.clusty.com' 
         WHEN 6 THEN 'www.archive.org' 
         WHEN 7 THEN 'www.mahalo.com' 
         WHEN 8 THEN 'www.google.com' 
         WHEN 9 THEN 'www.yahoo.com' 
         ELSE 'www.craftydba.com' 
        END AS my_link , 

     -- ratings scale 
        CASE (Number % 5) 
         WHEN 0 THEN 'poor' 
         WHEN 1 THEN 'fair' 
         WHEN 2 THEN 'good' 
         WHEN 3 THEN 'very good' 
         ELSE 'excellent' 
        END AS my_status 
      FROM TALLY AS T 
      WHERE Number <= 1000000 
go 

दूसरा, हम अपने परीक्षण वातावरण में प्रदर्शन विश्लेषण करते समय हमेशा बफर और कैश को साफ़ करना चाहते हैं। इसके अलावा, हम परिणामों की तुलना करने के लिए सांख्यिकी I/O और समय चालू करना चाहते हैं।

नीचे कोड देखें।

-- Show time & i/o 
SET STATISTICS TIME ON 
SET STATISTICS IO ON 
GO 

-- Remove clean buffers & clear plan cache 
CHECKPOINT 
DBCC DROPCLEANBUFFERS 
DBCC FREEPROCCACHE 
GO 

तीसरा, हम पहले TSQL कथन का प्रयास करना चाहते हैं। निष्पादन योजना को देखें और आंकड़ों को कैप्चर करें।

-- Try 1 
SELECT * FROM urls ORDER BY my_status 

/* 
Table 'urls'. Scan count 5, logical reads 4987, physical reads 1, read-ahead reads 4918, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
SQL Server Execution Times: 
CPU time = 3166 ms, elapsed time = 8130 ms. 
*/ 

enter image description here

चौथा, हम दूसरे TSQL बयान की कोशिश करना चाहते हैं। क्वेरी प्लान कैश और बफर साफ़ करने के लिए मत भूलना। यदि आप नहीं करते हैं, तो क्वेरी में 1 सेकंड से कम समय लगता है क्योंकि अधिकांश जानकारी स्मृति में होती है। निष्पादन योजना को देखें और आंकड़ों को कैप्चर करें।

-- Try 2 
SELECT ROW_NUMBER() OVER (ORDER BY my_status) as my_rownum, * FROM urls 

/* 
Table 'urls'. Scan count 5, logical reads 4987, physical reads 1, read-ahead reads 4918, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. 
SQL Server Execution Times: 
CPU time = 3276 ms, elapsed time = 8414 ms. 
*/ 

enter image description here

इतना ही नहीं बल्कि, यहाँ मज़ा हिस्सा है, प्रदर्शन विश्लेषण है।

1 - हम देख सकते हैं कि दूसरी योजना पहले का एक सुपर सेट है। इसलिए दोनों योजनाएं क्लस्टर इंडेक्स को स्कैन करती हैं और डेटा को सॉर्ट करती हैं। परिणामों को एक साथ रखने के लिए समांतरता का उपयोग किया जाता है।

2 - दूसरी योजना/क्वेरी पंक्ति संख्या की गणना करने की आवश्यकता है। यह डेटा को विभाजित करता है और इस स्केलर की गणना करता है। इसलिए, हम योजना में दो और ऑपरेटरों के साथ खत्म हो जाते हैं।

यह आश्चर्य की बात नहीं है कि पहली योजना 8130 एमएस में चलती है और दूसरी योजना 8414 एमएस में चलती है।

हमेशा पूछताछ योजना देखें। अनुमानित और वास्तविक दोनों। वे आपको बताते हैं कि इंजन करना चाहता है और वास्तव में क्या करता है।

इस उदाहरण में, दो अलग-अलग टीएसक्यूएल स्टेटमेंट लगभग समान योजनाओं के साथ आते हैं।

निष्ठा से

जॉन

www.craftydba.com

+1

मैं प्रयास की सराहना करता हूं, लेकिन यह वास्तव में सवाल का जवाब नहीं देता है इसके बारे में ऑर्डर करें (चाहे एक ROW_NUMBER फ़ंक्शन में सेट किए गए परिणाम पर) निर्धारिती है और यदि ROW_NUMBER और ORDER BY की प्रदर्शन तुलना के बजाय, कारक इसे प्रभावित नहीं करते हैं। हालांकि मैं यह भी जोड़ूंगा कि जब मैं आउटपुटफॉर्म ROW_NUMBER द्वारा आश्चर्यचकित हूं, तो 3.37% भिन्नता वाला एक परीक्षण मुझे निर्णायक प्रमाण के रूप में नहीं रोकता है! – GarethD

+0

प्रश्न दोबारा पढ़ना, मुझे लगता है कि मुझे निशान याद आया। उपयोगकर्ता वास्तव में दो प्रश्न जानना चाहता था; 1 - जोड़े गए रिकॉर्ड परिणाम में दिखाए जाते हैं और 2- लेनदेन इंजन की बात करते समय ROW_NUMBER से भिन्न द्वारा ऑर्डर किया जाता है। पहला सवाल इस्लामी स्तर पर निर्भर करता है। दूसरे प्रश्न का उत्तर मेरे प्रश्न विश्लेषण द्वारा दिया गया है। वे स्पष्ट रूप से एक समान योजना का उपयोग करते हैं। –

+0

वैसे मैं आपके साथ सहमत हूं @ user2577687 कि आपके द्वारा परीक्षण कई बार एक अच्छा अभ्यास है। लेकिन इसके दोष भी हैं। कभी-कभी पूछना ज्यादा इष्टतम होता है। उदाहरण के लिए आप प्रश्न लिख सकते हैं और कुछ मिनटों में जवाब का इंतजार कर सकते हैं और परीक्षण अधिक लंबा हो सकता है। और समय कभी-कभी बहुत महत्वपूर्ण बात होती है। विशेष रूप से यदि आप अपने लिए कुछ नहीं करते हैं लेकिन नियोक्ता के लिए :-) मैं प्रक्रिया चला रहा हूं जो 200 एमएलएन रिकॉर्ड से छोटे पैक में अपडेट होता है। यह धीमा, और धीमा चलाता है। इस बीच मैं एक बेहतर खोजने की कोशिश कर रहा हूँ। परीक्षण मुझे और भी धीमा कर देगा क्योंकि यह वर्तमान क्वेरी को रोकने की मांग करता है। – user1875438

0

किसी भी एसक्यूएल सवाल यह है कि "किस क्रम में यह उत्पादन करता है" के लिए सामान्य जवाब "जो कुछ भी सर्वर की तरह लगता है, और यह नहीं से एक ही हो सकता है पूछताछ करने के लिए क्वेरी "जब तक कि आपने विशेष रूप से आदेश का अनुरोध नहीं किया है।

यहां तक ​​कि कुछ आसान है जैसे 'myTable से शीर्ष 1000 myColumn' का चयन करें किसी भी क्रम में किसी भी पंक्ति के साथ वापस आ सकता है; उदाहरण के लिए सर्वर समानांतर धागे का उपयोग कर सकता है और लौटने के परिणाम शुरू करने के लिए पहला धागा तालिका के बीच में पढ़ना शुरू कर दिया था, या एक इंडेक्स का उपयोग किया गया था जिसमें मेरा कॉलम शामिल था, इसलिए आपको पंक्तियों को वर्णमाला के पहले उत्पादनाम के साथ मिला (इस बार; पिछली बार इंडेक्स के अलग-अलग आंकड़े थे इसलिए उसने एक अलग इंडेक्स चुना और आपको 1000 सबसे पुराने लेनदेन दिए ...)

यह सर्वर के लिए सैद्धांतिक रूप से संभव है कि "मेरे पास मेरे मेमोरी कैश में इन 10 पेज थे जो आपकी क्वेरी से मेल खाते हैं, मैं आपको इन्हें पास कर दूंगा जबकि मैं डिस्क को बाकी लौटने की प्रतीक्षा करता हूं ...

संबंधित मुद्दे