निकटतम मानों को खोजने के लिए SQL सर्वर में क्वेरी कैसे लिखें


16

मान लें कि मेरे पास एक तालिका में निम्नलिखित पूर्णांक मान हैं

32
11
15
123
55
54
23
43
44
44
56
23

ठीक है, सूची चल सकती है; इससे कोई फर्क नहीं पड़ता। अब मैं इस तालिका को क्वेरी करना चाहता हूं और मैं निश्चित संख्या में लौटना चाहता हूं closest records। मान लें कि मैं 10 निकटतम रिकॉर्ड मैचों को अंक 32 पर वापस करना चाहता हूं। क्या मैं इसे कुशलता से प्राप्त कर सकता हूं?

यह SQL Server 2014 में है।

जवाबों:


21

यह मानकर कि कॉलम अनुक्रमणित है कि निम्नलिखित यथोचित कुशल होना चाहिए।

10 पंक्तियों के दो कांटों के साथ और फिर एक प्रकार का (20 तक) वापस आ गया।

WITH CTE
     AS ((SELECT TOP 10 *
          FROM   YourTable
          WHERE  YourCol > 32
          ORDER  BY YourCol ASC)
         UNION ALL
         (SELECT TOP 10 *
          FROM   YourTable
          WHERE  YourCol <= 32
          ORDER  BY YourCol DESC))
SELECT TOP 10 *
FROM   CTE
ORDER  BY ABS(YourCol - 32) ASC 

(यानी संभावित रूप से नीचे जैसा कुछ)

यहाँ छवि विवरण दर्ज करें

या एक और संभावना (कि अधिकतम 10 की तरह छंटनी पंक्तियों की संख्या कम कर देता है)

WITH A
     AS (SELECT TOP 10 *,
                       YourCol - 32 AS Diff
         FROM   YourTable
         WHERE  YourCol > 32
         ORDER  BY Diff ASC, YourCol ASC),
     B
     AS (SELECT TOP 10 *,
                       32 - YourCol AS Diff
         FROM   YourTable
         WHERE  YourCol <= 32
         ORDER  BY YourCol DESC),
     AB
     AS (SELECT *
         FROM   A
         UNION ALL
         SELECT *
         FROM   B)
SELECT TOP 10 *
FROM   AB
ORDER  BY Diff ASC

यहाँ छवि विवरण दर्ज करें

एनबी: ऊपर निष्पादन योजना सरल तालिका परिभाषा के लिए थी

CREATE TABLE [dbo].[YourTable](
    [YourCol] [int] NOT NULL CONSTRAINT [SomeIndex] PRIMARY KEY CLUSTERED 
)

तकनीकी रूप से, नीचे की शाखा पर छाँटे जाने की आवश्यकता नहीं होनी चाहिए क्योंकि वह भी डिफ द्वारा आदेशित है, और दो ऑर्डर किए गए परिणामों को मर्ज करना संभव होगा। लेकिन मैं उस योजना को पाने में सक्षम नहीं था।

क्वेरी के पास ORDER BY Diff ASC, YourCol ASCबस नहीं है ORDER BY YourCol ASC, क्योंकि योजना के शीर्ष शाखा में सॉर्ट से छुटकारा पाने के लिए काम करना समाप्त हो गया था। मुझे द्वितीयक कॉलम को जोड़ने की आवश्यकता थी (भले ही यह कभी भी परिणाम नहीं बदलेगा क्योंकि YourColसमान डिफ के साथ सभी मानों के लिए समान होगा) इसलिए यह एक सॉर्ट को जोड़े बिना मर्ज ज्वाइन (कॉन्सेप्टन) के माध्यम से जाएगा।

SQL सर्वर यह पता लगाने में सक्षम होता है कि आरोही क्रम में X पर खोजा गया सूचकांक X + Y द्वारा आदेशित पंक्तियों को वितरित करेगा और किसी प्रकार की आवश्यकता नहीं है। लेकिन यह अनुमान लगाने में सक्षम नहीं है कि अवरोही क्रम में सूचकांक की यात्रा उसी क्रम में पंक्तियों को वितरित करेगी जैसे कि YX (या यहां तक ​​कि सिर्फ एक शून्य से कम एक्स)। योजना की दोनों शाखाएँ क्रम से बचने के लिए एक सूचकांक का उपयोग करती हैं लेकिन TOP 10नीचे की शाखा में तब क्रमबद्ध होती हैं Diff(भले ही वे पहले से ही उस क्रम में हों) मर्ज के लिए वांछित क्रम में प्राप्त करने के लिए।

अन्य प्रश्नों / तालिका परिभाषाओं के लिए यह मुश्किल हो सकता है या केवल एक शाखा के साथ मर्ज योजना प्राप्त करना संभव नहीं है - क्योंकि यह एक ऑर्डरिंग अभिव्यक्ति खोजने पर निर्भर करता है जो SQL सर्वर:

  1. यह स्वीकार करता है कि सूचकांक चाहने वाले निर्दिष्ट क्रम की आपूर्ति करेंगे ताकि शीर्ष से पहले किसी प्रकार की आवश्यकता न हो ।
  2. मर्ज ऑपरेशन में उपयोग करने के लिए खुश है ताकि बाद में किसी प्रकार की आवश्यकता न हो TOP

1

मैं थोड़ा हैरान और हैरान हूं कि हमें इस मामले में यूनियन करना है। निम्नलिखित सरल और अधिक कुशल है

SELECT TOP (@top) *
FROM @YourTable
ORDER BY ABS(YourCol-@x)

दोनों प्रश्नों की तुलना करने के लिए पूरा कोड और निष्पादन योजना निम्नलिखित है

DECLARE @YourTable TABLE (YourCol INT)
INSERT @YourTable (YourCol)
VALUES  (32),(11),(15),(123),(55),(54),(23),(43),(44),(44),(56),(23)

DECLARE @x INT = 100, @top INT = 5

--SELECT TOP 100 * FROM @YourTable
SELECT TOP (@top) *
FROM @YourTable
ORDER BY ABS(YourCol-@x)

;WITH CTE
     AS ((SELECT TOP 10 *
          FROM   @YourTable
          WHERE  YourCol > 32
          ORDER  BY YourCol ASC)
         UNION ALL
         (SELECT TOP 10 *
          FROM   @YourTable
          WHERE  YourCol <= 32
          ORDER  BY YourCol DESC))
SELECT TOP 10 *
FROM   CTE
ORDER  BY ABS(YourCol - 32) ASC 

निष्पादन योजना की तुलना


-3

मार्टिन के दूसरे सुझाव का शोधन:

WITH AB
     AS (SELECT *, ABS(32 - YourCol) AS Offset
         FROM   YourTable),
SELECT TOP 10 *
FROM   AB
ORDER  BY Offset ASC

2
यह थोड़ा सरल कोड हो सकता है लेकिन यह बहुत कम कुशल होने वाला है। हम SELECT TOP 10 * FROM YourTable ORDER BY ABS(YourCol - 32) ;और भी सरल उपयोग कर सकते हैं । कुशल भी नहीं।
ypercube y
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.