2012-04-27 6 views
5

निम्न क्वेरी एक सही परिणाम देता है लेकिन मैं एक ही परिणाम को तेजी से कैसे प्राप्त करूं?आज इस सप्ताह, इस महीने, इस तिमाही के आधार पर बिक्री को सारांशित करने का सबसे तेज़ तरीका?

लक्ष्य आज इस सप्ताह, महीने और तिमाही में अपनी बिक्री को सारांशित करके विक्रेताओं की प्रगति को ट्रैक करने के लिए एक तालिका आउटपुट करना है।

SellerID Today     ThisWeek    ThisMonth    ThisQuarter 
----------- --------------------- --------------------- --------------------- --------------------- 
1   400,00    700,00    900,00    900,00 
2   950,00    1850,00    2650,00    2650,00 

मेरे प्रश्न:

CREATE TABLE #sales(
    [Price] MONEY, 
    [Date] DATE, 
    [SellerID] INT 
) 

INSERT INTO #sales VALUES 
(100, '2012-01-01', 1), 
(200, '2012-04-01',1), 
(300, '2012-04-23',1), 
(400, '2012-04-27',1), 
(700, '2012-01-01', 2), 
(700, '2012-01-02', 2), 
(800, '2012-04-01',2), 
(900, '2012-04-23',2), 
(950, '2012-04-27',2) 


SELECT 
SellerID AS SellerID, 

SUM(CASE WHEN [Date] >= DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()),0) THEN [Price] END) AS Today, 
SUM(CASE WHEN [Date] >= DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0) THEN [Price] END) AS ThisWeek, 
SUM(CASE WHEN [Date] >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0) THEN [Price] END) AS ThisMonth, 
SUM(CASE WHEN [Date] >= DATEADD(QUARTER, DATEDIFF(QUARTER, 0, GETDATE()), 0) THEN [Price] END) AS ThisQuarter 

FROM #sales 
WHERE DATEPART(YEAR, [Date]) = DATEPART(YEAR, GETDATE()) 
GROUP BY SellerID 

जब एक बड़ी मेज यह काफी धीमी गति से हो जाता है पर एक ही प्रश्न को क्रियान्वित। बस सीएएसई-स्टेटमेंट को हटाने से लगभग 50% निष्पादन समय में कटौती होती है।

मैं एक ही परिणाम को तेज़ी से और अधिक कुशल तरीके से कैसे प्राप्त कर सकता हूं?

+2

जब तक आपकी '[तिथि]' कॉलम अनुक्रमित हो, मुझे लगता है कि आपके पास लेनदेन संबंधी डेटा पूछताछ के लिए पहले से ही सबसे कुशल समाधान है। यदि आप प्रदर्शन समस्याओं को मार रहे हैं तो आप डेटा वेयरहाउसिंग को एक्सप्लोर करना चाहेंगे। – GarethD

+1

हां यह अनुक्रमित है। हम एसक्यूएल एज़ूर पर हैं जो दुर्भाग्य से इस समय सीमित है। मुझे यह भी लगता है कि यह एक बेहतर दृष्टिकोण होगा (+1)। –

उत्तर

8

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

CREATE TABLE Dim.Date 
(  DateKey  DATE NOT NULL, 
     DayOfWeek VARCHAR(20) NOT NULL, 
     Day   TINYINT NOT NULL, 
     Week  TINYINT NOT NULL, 
     Quarter  TINYINT NOT NULL, 
     Month  TINYINT NOT NULL, 
     Year  SMALLINT NOT NULL 
    CONSTRAINT PK_Dim_Date_DateKey PRIMARY KEY (DateKey) 
) 
CREATE TABLE Fact.Sales 
(  DateKey  DATE NOT NULL, 
     SellerID INT NOT NULL, 
     Sales  INT NOT NULL, 
     Amount  MONEY NOT NULL, 
    CONSTRAINT PK_Fact_Sales PRIMARY KEY (DateKey, SellerID), 
    CONSTRAINT FK_Fact_Sales_DateKey FOREIGN KEY (DateKey) REFERENCES Dim.Date 
) 

डेटा मान लिया जाये कि पिछली तारीख का नहीं होगा तो आप इस तरह एक प्रक्रिया का उपयोग कर सकते एक अनुसूचित काम पर अपने गोदाम भरने के लिए:

DECLARE @MaxDate DATE 
SELECT @MaxDate = DATEADD(DAY, 1, MAX(DateKey)) 
FROM Fact.Sales 

INSERT INTO Dim.Date 
SELECT DATEADD(DAY, Increment, @MaxDate), 
     DATENAME(WEEKDAY, DATEADD(DAY, Increment, @MaxDate)), 
     DATEPART(DAY, DATEADD(DAY, Increment, @MaxDate)), 
     DATEPART(WEEK, DATEADD(DAY, Increment, @MaxDate)), 
     DATEPART(MONTH, DATEADD(DAY, Increment, @MaxDate)), 
     DATEPART(QUARTER, DATEADD(DAY, Increment, @MaxDate)), 
     DATEPART(YEAR, DATEADD(DAY, Increment, @MaxDate)) 
FROM ( SELECT ROW_NUMBER() OVER(ORDER BY Object_ID) - 1 [Increment] 
      FROM Sys.Objects 
     ) obj 
WHERE NOT EXISTS 
     ( SELECT 1 
      FROM Dim.Date 
      WHERE Date.DateKey = DATEADD(DAY, Increment, @MaxDate) 
     ) 


INSERT INTO Fact.Sales 
SELECT [Date], SellerID, COUNT(*), SUM(Price) 
FROM LiveDatabase..Sales 
WHERE [Date] >= @MaxDate 
GROUP BY [Date], SellerID 

यह निम्न क्वेरी के साथ छोड़ अपनी रिपोर्ट का उत्पादन करने के लिए

SELECT SellerID, 
     SUM(CASE WHEN Today.DateKey = Date.DateKey THEN Amount ELSE O END) [Today], 
     SUM(CASE WHEN Today.Week = Date.Week THEN Amount ELSE O END) [ThisWeek], 
     SUM(CASE WHEN Today.Month = Date.Month THEN Amount ELSE O END) [ThisMonth], 
     SUM(CASE WHEN Today.Quarter = Date.Quarter THEN Amount ELSE O END) [ThisQuarter], 
     SUM(CASE WHEN Today.Year = Date.Year THEN Amount ELSE O END) [ThisYear] 
FROM Fact.Sales 
     INNER JOIN Dim.Date 
      ON Date.DateKey = Sales.DateKey 
     INNER JOIN Dim.Date Today 
      ON Today.DateKey = CAST(GETDATE() AS DATE) 
      AND Today.Year = Date.Year 
GROUP BY SellerID 

ऐसा लगता है कि मूल क्वेरी की तुलना में कुछ भी जटिल है, लेकिन जितना अधिक ऑनलाइन डेटाबेस बढ़ता है उतना ही आपको लाभ दिखाई देगा। मैंने फायदे दिखाने के लिए SQL Fiddle किया है, यह 10000 यादृच्छिक बिक्री रिकॉर्ड के साथ लाइव डेटा भरता है, फिर एक गोदाम बनाता है (स्कीमा बनाने में कुछ सेकंड लग सकते हैं)। आपको नोटिस करना चाहिए कि वेयरहाउस पर क्वेरी का निष्पादन समय काफी तेज़ है (c.20x)।यह पहले रन पर 20x तेज नहीं हो सकता है, लेकिन एक बार क्वेरी प्लान दोनों प्रश्नों के लिए कैश किया गया है, तो वेयरहाउस क्वेरी लगातार 20x तेज है (वैसे भी मेरे लिए है)।

+0

Awsome उत्तर! धन्यवाद गैरेथ! –

2

डेटा का डी-सामान्यीकृत संस्करण रखें?

जैसे:

select 
    year 
    ,sum(price) 
from 
    deNormalised 
where 
    quarter = 1 
group by 
    year 

साल भर पहले क्वार्टर की तुलना

जाहिर है इसका मतलब है आप के साथ आने के लिए है पाने के लिए: http://sqlfiddle.com/#!3/300a5/2

select 
    * 
    ,DATENAME(day, [date]) as day 
    ,DATENAME(month, [date]) as month 
    , DATENAME(year, [date]) as year 
    ,DATENAME(quarter, [date]) as quarter 
into deNormalised 
from #sales 

तो आप की तरह क्वेरी चला सकते हैं डेटा के डी-सामान्यीकृत संस्करण को बनाए रखने के लिए एक शेड्यूल। आप इसे अद्यतन या हर घंटे एक ट्रिगर के साथ कर सकते हैं।

आप डी-सामान्यीकृत परिणामों में नवीनतम डेटा जोड़ने का भी प्रयास कर सकते हैं .. इस तरह आप केवल आज बनाई गई पंक्तियों पर धीमी प्रसंस्करण कर रहे हैं।

संपादित करें: मुझे नहीं पता कि DATENAME फ़ंक्शंस का उपयोग करने से आपकी मौजूदा संरचना का उपयोग करके प्रदर्शन में सुधार होगा।

+0

यह एक अच्छा समाधान है। हम वास्तव में आज कुछ डेटा के लिए denormalised संस्करण बना रहे हैं। यह डेटा अक्सर अद्यतन और एक्सेस किया जाता है, इसलिए संभवतः वेब अनुरोध पर कैश का उपयोग करने के लिए सबसे आसान बात यह है कि इसे प्रत्येक अनुरोध के लिए निष्पादित करने से रोका जाए? –

+0

कैशिंग वेब अनुरोधों का भी सरल संस्करण केवल उसी पैरामीटर के लिए काम करता है .. denormalised डेटा सभी प्रश्नों पर बेहतर प्रदर्शन करेगा। – gordatron

+0

मैं एक विशेषज्ञ नहीं हूं और इसे किसी बड़े पैमाने पर ऐप्स पर अभ्यास में नहीं डालता है, इसलिए हो सकता है कि कुछ वास्तविक दुनिया अनुभव वाले कुछ लोग कुछ उत्तरों में डाल सकें। – gordatron

0
select 
    SellerID 
    ,sum(case when [Date]=getdate() then [Price] else 0 end) as Today 
    ,sum(case when datepart(week,[Date])=datepart(week,getdate()) then [Price] else 0 end) as ThisWeek 
    ,sum(case when datepart(MONTH,[Date])=datepart(month,getdate()) then [Price] else 0 end) as ThisMonth 
    ,sum(case when datepart(QUARTER,[Date])=datepart(QUARTER,getdate()) then [Price] else 0 end) as ThisQUARTER 
from #sales 
Group by SellerID 
संबंधित मुद्दे