2012-02-16 5 views
5

चुनता है मेरे पास एक सारणी है जिसमें बहुत अधिक डेटा है, जहां हम विशेष रूप से date फ़ील्ड की परवाह करते हैं। इसका कारण यह है कि डेटा वॉल्यूम सिर्फ ~ 30x ऊपर चला गया, और पुराने तरीके जल्द ही अलग हो जाएंगे। क्वेरी मुझे आशा है कि तुम मेरे लिए की जरूरत है अनुकूलित करने में सहायता कर सकते हैं:एक क्वेरी को अनुकूलित करने का प्रयास करना जो 'अनुमानित निकटतम रिकॉर्ड'

  • एक (एक CTE आधारित तालिका-मान समारोह द्वारा उत्पन्न)
  • तिथियों की सूची लेने के उन तारीखों में से प्रत्येक के लिए एक ही रिकॉर्ड को पुनः प्राप्त
    • 'निकटतम' के कुछ परिभाषा

उदाहरण के लिए, के आधार पर वर्तमान तालिका 5 सेकंड में डेटा होता है (+/- एक छोटे से) अंतराल। मुझे उस तालिका का नमूना लेने और रिकॉर्ड प्राप्त करने की आवश्यकता है जो 30 सेकंड अंतराल के करीब आता है।

मेरे पास अभी क्या ठीक है ठीक काम करता है। अगर मैं इसे और अधिक अनुकूलित करने का कोई तरीका हूं तो मैं बस उत्सुक हूं। अगर मैं इसे लिंक से एसक्यूएल में कर सकता हूं, तो यह भी साफ होगा। मुझे मूल्य मानों की मात्रा (~ 2 मिलियन पंक्तियां मिनट) दिए गए इंडेक्स पर सुझावों में भी रूचि है।

declare @st datetime ; set @st = '2012-01-31 05:05:00'; 
declare @end datetime ; set @end = '2012-01-31 05:10:00'; 

select distinct 
    log.* -- id, 
from 
    dbo.fn_GenerateDateSteps(@st, @end, 30) as d 
     inner join lotsOfLogData log on l.Id = (
      select top 1 e.[Id] 
      from 
       lotsOfLogData as log -- contains data in 5 second intervals 
      where 
       log.stationId = 1000 
       -- search for dates in a certain range 
       AND utcTime between DateAdd(s, -10, dt) AND DateAdd(s, 5, dt) 
      order by 
       -- get the 'closest'. this can change a little, but will always 
       -- be based on a difference between the date 
       abs(datediff(s, dt, UtcTime)) 
     ) 
    -- updated the query to be correct. stadionId should be inside the subquery 

lotOfLogData की तालिका संरचना नीचे है। अपेक्षाकृत कुछ स्टेशन आईडी (शायद 50) हैं, लेकिन प्रत्येक के लिए बहुत सारे रिकॉर्ड हैं। जब हम पूछते हैं तो हम स्टेशन आईडी को जानते हैं।

create table ##lotsOfLogData (
    Id   bigint  identity(1,1) not null 
, StationId int   not null 
, UtcTime  datetime not null 
    -- 20 other fields, used for other calculations 
) 

fn_GenerateDateSteps इस तरह एक डाटासेट देता है, पैरामीटर के लिए दिया:

[DT] 
2012-01-31 05:05:00.000 
2012-01-31 05:05:30.000 
2012-01-31 05:06:00.000 
2012-01-31 05:06:30.000 (and so on, every 30 seconds) 

मैं यह एक अस्थायी तालिका के साथ साथ ही इस तरह से किया है,, लेकिन वह सिर्फ एक छोटे से बाहर आया थोड़ा और महंगा

declare @dates table (dt datetime, ClosestId bigint); 
insert into @dates (dt) select dt from dbo.fn_GenerateDateSteps(@st, @end, 30) 
update @dates set closestId = (-- same subquery as above) 
select * from lotsOfLogData inner join @dates on Id = ClosestId 

संपादित करें: अप फिक्स्ड

गॉट 200K + अब के साथ काम करने पंक्तियों। मैंने दोनों तरीकों की कोशिश की, और क्रॉस एक उचित इंडेक्स के साथ लागू होता है (आईडी/समय + शामिल है (.. सभी कॉलम ...) ने ठीक काम किया। हालांकि, मैंने एक सरल (और मौजूदा) का उपयोग करके शुरू की गई क्वेरी के साथ समाप्त किया। । [आईडी + समय] पर सूचकांक क्यों मुझे लगता है कि एक पर बसे अधिक व्यापक रूप से समझा जा सकता क्वेरी है हो सकता है कि वहाँ अभी भी यह करने के लिए एक बेहतर तरीका है, लेकिन मैं यह नहीं देख सकते हैं:। डी

-- subtree cost (crossapply) : .0808 
-- subtree cost (id based) : .0797 

-- see above query for what i ended up with 

उत्तर

1

आप

  • कोशिश inner join एक cross apply के लिए बदल सकता है।
  • उप-चयन में where log.stationid को ले जाएं।

एसक्यूएल वक्तव्य

SELECT DISTINCT log.* -- id, 
FROM dbo.fn_GenerateDateSteps(@st, @end, 30) AS d 
     CROSS APPLY (
      SELECT TOP 1 log.* 
      FROM lotsOfLogData AS log -- contains data in 5 second intervals 
      WHERE -- search for dates in a certain range 
        utcTime between DATEADD(s, -10, d.dt) AND DATEADD(s, 5, d.dt) 
        AND log.stationid = 1000 
      ORDER BY 
        -- get the 'closest'. this can change a little, but will always 
        -- be based on a difference between the date 
        ABS(DATEDIFF(s, d.dt, UtcTime)) 
     ) log 
+0

क्रॉस लागू होता है कि मैं स्टेशन/समय पर एक इंडेक्स बनाना चाहता हूं तालिका में * सभी * अन्य डेटा शामिल है। इंडेक्स के बिना, यह नग्न क्वेरी के समान ही चलता है, इसलिए इस मामले में क्रॉस काम नहीं करेगा :) मुझे इसके बारे में भी पता नहीं था, इसलिए धन्यवाद! –

+0

ओह, और मेरे पास उस क्वेरी में एक बग था;) मैं * आवश्यक * स्टेशन को subquery में डालने के लिए आवश्यक हूं क्योंकि अन्यथा मैं किसी भी स्टेशन से मेल खाऊंगा जो कि सीमा में है। ऐसा करने के बाद, उचित सूचकांक का उपयोग किया जाता है और सब कुछ सुपर फास्ट (आईएसएच) –

+0

@AndrewBacker - दूर हो गया लेकिन हमें सूचित रखने के लिए धन्यवाद। –

1

बस कुछ विचार ... वास्तव में यह एक जवाब नहीं कहेंगे लेकिन यह टिप्पणी बॉक्स के लिए बहुत बड़ा था।

सबसे पहले, यदि आप पहले से ऐसा नहीं कर चुके हैं तो मैं क्वेरी के लिए निष्पादन योजना को देखूंगा।

अधिक गूढ़: क्या आपके पास तारीखों को आदिम मानों के रूप में प्रस्तुत करने का विकल्प है (जैसे एक पूर्णांक परिभाषित समय के बाद सेकंड/मिनट का प्रतिनिधित्व करने वाला एक पूर्णांक)? भले ही मुझे लगता है कि एसक्यूएल सर्वर स्टोर्स की तारीख हुड के नीचे संख्यात्मक मानों के रूप में होती है, एक आदिम पर संचालन थोड़ा तेज़ हो सकता है क्योंकि यह दोहराए गए कॉल को DateAdd() और DateDiff() पर समाप्त कर देगा।

This (fairly old) article उदाहरण देता है कि SQL सर्वर वास्तव में तारीखों को कैसे संग्रहीत करता है। शायद आप अपनी तिथियों को DATETIME के ​​रूप में छोड़ सकते हैं लेकिन बुनियादी गणित के साथ उन पर काम कर सकते हैं।

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

मैं आपके डेटा का प्रतिनिधित्व करने के लिए उपयोग किए जाने वाले स्टार स्कीमा को भी देख सकता हूं, दिनांक दिनांक सामान्यता वाले दिनांक आयाम के साथ। फिर आप सामान्यीकरण के खिलाफ खोज सकते हैं। यहां तक ​​कि यदि सामान्यीकरण का उपयोग नहीं किया गया था, तो तारीखों की वास्तविक संख्या कम हो जाएगी क्योंकि उसी तारीख के सभी तथ्यों में आयाम में एक ही रिकॉर्ड को इंगित किया जा सकता है, इस प्रकार दिनांक केवल एक बार मूल्यांकन किया जाना चाहिए।

आखिरकार, एसक्यूएल प्रदर्शन ट्यूनिंग विज़ार्ड (मुझे विश्वास है कि यह 2005 में है, मुझे पता है कि यह 2008 में है) आपकी क्वेरी के लिए सुझाव देता है? मैं अपने सुझावों को अंधाधुंध रूप से कार्यान्वित करने की अनुशंसा नहीं करता हूं, लेकिन मुझे अक्सर उन चीजों में अच्छे विचार मिलते हैं जो इसकी सिफारिश करते हैं।

+0

दुर्भाग्य से मैं डेटा स्वरूप के साथ ज्यादा कुछ नहीं कर सकते हैं। एक बाहरी सेवा डेटा प्राप्त करती है और हमारे लिए वहां लॉग करती है। मैंने निष्पादन योजना को देखा है, लेकिन यह बहुत बड़ा है =) मुझे स्टेशन आईडी पर एक क्लस्टर्ड इंडेक्स मिला है, और एक std। तिथि पर सूचकांक। मेरे पास अभी तक इसका परीक्षण करने के लिए पर्याप्त यथार्थवादी डेटा नहीं है, और एक छोटे से सेट के साथ यह कोई फर्क नहीं पड़ता कि कोई सूचकांक है या नहीं –