2017-10-31 6 views
0

私は、いくつかの異なるテーブルから多くの異なるデータを取得するストアドプロシージャを構築しています。売上テーブルから販売情報を取り出し、その販売データに対してさまざまな集計を実行する方法が必要です。下の例では、私は一時テーブルを使用してこれを達成していますが、誰かがおそらくより良い方法があると示唆しています。私がここでやっていることを達成するためのより効率的な方法がありますか?一時テーブルは最適なソリューションですか?

SELECT * INTO #TempSales FROM [Sales] WHERE ClientId = @ClientId 
    SELECT 
     [Customer].[CustomerID], 
     [Customer].[AccountBalAmountOpen], 
     [Customer].[AccountAgeAmountDays0], 
     [Customer].[AccountAgeAmountDays30], 
     [Customer].[AccountAgeAmountDays60], 
     [Customer].[AccountAgeAmountDays90], 
     [Customer].[AccountAgeAmountDaysOver90], 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 385) AS ServiceLifeTimeSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 385 AND MONTH(SaleDate) = MONTH(GETDATE()) AND YEAR(SaleDate) = YEAR(GETDATE())) AS ServiceMonthToDateSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 385 AND YEAR(SaleDate) = YEAR(GETDATE())) AS ServiceYearToDateSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 385 AND YEAR(SaleDate) = (YEAR(GETDATE()) - 1)) AS ServicePreviousYearSales, 
    (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 460) AS PartsLifeTimeSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 460 AND MONTH(SaleDate) = MONTH(GETDATE()) AND YEAR(SaleDate) = YEAR(GETDATE())) AS PartsMonthToDateSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 460 AND YEAR(SaleDate) = YEAR(GETDATE())) AS PartsYearToDateSales, 
     (SELECT SUM(SalesAmount) FROM #TempSales WHERE CustomerId = [Customer].[CustomerID] AND Origin = 460 AND YEAR(SaleDate) = (YEAR(GETDATE()) - 1)) AS PartsPreviousYearSales, 
     [Orders].[CustomerId] AS ParentCustomerId, 
     [Orders].[OrderId], 
     [Orders].[OrderStatus], 
     [Orders].[UnitId], 
     [Orders].[FleetId], 
     [Orders].[CreatedDate] AS OrderCreatedDate, 
     [Orders].[OrderType], 
     [OrderParts].[OrderId] AS ParentOrderId, 
     [OrderParts].[PartId], 
     [OrderParts].[PartDescription], 
     [OrderParts].[QuantityShip], 
     [OrderParts].[QuantityBackOrder], 
     [OrderParts].[CreatedDate] AS PartCreatedDate 
     FROM [Customer] 
     LEFT JOIN [Orders] 
     ON [Orders].[CustomerId] = [Customer].[CustomerID] 
     LEFT JOIN [OrderParts] 
     ON [OrderParts].[OrderId] = [Orders].[OrderId] 
     WHERE [Customer].[ClientID] = @ClientId 
DROP TABLE #TempSales 
+2

ストアドプロシージャのような手続き型コードは**ベンダー固有のもの** ** - mysql、postgresql、sql-server、oracle、またはdb2のいずれを使用するかを指定するタグを追加してください' - または全く別のもの。 –

+2

選択した文字列内のサブクエリはほとんど処理を進める最善の方法ではありません – Twelfth

+0

とにかく1回の処理で必要なすべての処理を実行できるようです。単一のclientidの最初の選択フィルター。 2番目の選択は他のすべてを行います。クライアントIDフィルタを2番目の選択に追加して、1つのクエリでそれを行うのはなぜですか?遅すぎる?パフォーマンスチューニング(インデックスの追加など) –

答えて

0

一時テーブルは他のクエリで再利用されようとしている複雑なクエリの中間結果を格納するのに便利ですが、私はあなたが一時テーブルとして作成されているとして、あなたの計算のためにそれを必要とすることはないと思いますこれは:

SELECT * INTO #TempSales FROM [Sales] WHERE ClientId = @ClientId 

あなたは何もして、テーブルを結合したり、テーブルが適切にインデックスされるので、もし、計算を行うか、集約関数を使用していない(少なくともClientIdは、CustomerIdOriginSalesDate)、クエリが正常に実行する必要がありますかあなたが作成したテーブルが手動で追加しない限り、SELECT INTOにはインデックスがありません。

しかし、あなたは、このような条件を持っているので、おそらくあなたは、一時テーブルを使用して速度改善を経験している:

AND YEAR(SaleDate) = YEAR(GETDATE()) 
AND MONTH(SaleDate) = MONTH(GETDATE()) AND YEAR(SaleDate) = YEAR(GETDATE()) 

make the query non-sargableあなたが関数内のフィルターカラムを囲むされます。このため、クエリオプティマイザはSaleDateの既存のインデックスを正しく使用できず、一時テーブルの行数が少なくなるため、Salesテーブルよりフルスキャンを実行する時間が短くなります。

あなたはフィルターカラム(あなたが一定の値に関数を使用することができますが)に任意の関数を適用していない状態使用していることを修正することができます:

declare @thisYearStart as datetime, @nextYearStart as datetime, 
    @thisMonthStart as datetime, @nextMonthStart as datetime 

set @thisYearStart=DATEFROMPARTS(YEAR(GETDATE()),1,1) 
set @nextYearStart=DATEADD(year,1,@thisYearStart) 
set @thisMonthStart=DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()),1) 
set @nextMonthStart=DATEADD(month,1,@thisMonthStart) 

か、SQL古いのバージョンを使用している場合をもしその

AND SaleDate>[email protected] AND SaleDate<@nextYearStart 
AND SaleDate>[email protected] AND SaleDate<@nextMonthStart 

注:その後、

set @thisYearStart=CAST(CAST(YEAR(GETDATE()) as char(4))+'0101' AS datetime) -- ISO format 
set @nextYearStart=DATEADD(year,1,@thisYearStart) 
set @thisMonthStart=DATEADD(month,MONTH(GETDATE())-1,@thisYearStart) 
set @nextMonthStart=DATEADD(month,1,@thisMonthStart) 

とだけ使用します。SQL Server 2012のより変数を使用する必要はありません。WHEREの条件で直接DATEFROMPARTS(...)を使用できますが、それらを使用してストアドプロシージャを作成しているので、クエリをより読みやすくします。

関連する問題