C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[2]: 3つのテーブルを結合すると極端に遅くなるクエリー


(過去ログ 103 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■61442 / inTopicNo.1)  3つのテーブルを結合すると極端に遅くなるクエリー
  
□投稿者/ えれこぜ (1回)-(2011/08/13(Sat) 12:12:10)

分類:[データベース全般] 

お世話になります。

開発環境:
SQL Server 2000、VS2005、VB2005

SELECT
	TargetDate.Ymd AS 対象日付
	,ISNULL(SEGMENT.Kya,0) AS 客数
	,ISNULL(SEGMENT.Sur,0) AS 売上数
	,ISNULL(SEGMENT.Kgk,0) AS 売上額
	,ISNULL(SEGMENT.Ara,0) AS 粗利額
	,TOTAL.Kya AS 全体客数
FROM (A) AS TargetDate
LEFT OUTER JOIN (B) AS SEGMENT 
	ON TargetDate.Ymd = SEGMENT.Ymd
INNER JOIN (C) AS TOTAL 
	ON TargetDate.Ymd = TOTAL.Ymd
ORDER BY TargetDate.Ymd

上記クエリーにて(A)対象日付,(B)部分実績,(C)全体実績 の
3つのテーブルを結合して、日別売上実績を抽出しています。

それぞれを単体発行すると、
A:対象日付 3864887行(T明細) → 31行 1秒
B:部分実績 3864887行(T明細) → 31行 33秒
C:全体実績 3682行(T日報) → 31行 1秒
にて取得できるのですが、3つのテーブルを結合すると、何故か273秒もかかります。

取得件数が少ないので、それぞれクエリーを3回発行してプログラムで結合させれば、済む話なのですが、
1回のクエリで取得するとプログラムより遅くなる原因がわかりません。
個人的に気になるのが、結合するとA、B、Cそれぞれの実行プランが実行回数4になることです。

何か調査方法・解決方法などありましたら、よろしくお願い致します。

【Aのクエリー】
SELECT
TBL.Ymd as Ymd
FROM PosTranData AS TBL
WHERE 1=1
AND TBL.Ymd BETWEEN '20110701' AND '20110731'
GROUP BY
TBL.Ymd

【Bのクエリー】
SELECT
	ReceSum.Ymd as Ymd
	,SUM(ReceSum.Kya) as Kya
	,SUM(ReceSum.Sur) as Sur
	,SUM(ReceSum.Kgk) as Kgk
	,SUM(ReceSum.Ara) as Ara
FROM
	(
		SELECT
			TBL.Ymd as Ymd
			,1 as Kya
			,SUM(TBL.Sur) as Sur
			,SUM(TBL.Kgk) as Kgk
			,SUM(TBL.Kgk-TBL.Sur*TBL.GenTan) as Ara
		FROM PosTranData AS TBL
		LEFT OUTER JOIN 商品マスター AS SHO ON TBL.Jan=SHO.Jan
		WHERE 1=1
		AND TBL.Ymd BETWEEN '20110701' AND '20110731'
		AND LEFT(SHO.Bun,2) = '01' 
		GROUP BY
		TBL.Ymd
		,TBL.Ten
		,TBL.Pos
		,TBL.Receipt
	) AS ReceSum
GROUP BY ReceSum.Ymd 

【Cのクエリー】
SELECT
TBL.Ymd as Ymd
,SUM(TBL.Kya) as Kya
,SUM(TBL.Sur) as Sur
,SUM(TBL.Kgk) as Kgk
,SUM(TBL.Ara) as Ara
FROM DailyReport AS TBL
WHERE 1=1
AND TBL.Ymd BETWEEN '20110701' AND '20110731'
GROUP BY TBL.Ymd 

【SQLテーブル情報】
PosTranData(クラスタ化インデックス、一意):Ymd,Ten,Pos,Receipt,Gyo
DailyReport(クラスタ化インデックス、一意):Ymd,Ten

引用返信 編集キー/
■61443 / inTopicNo.2)  Re[1]: 3つのテーブルを結合すると極端に遅くなるクエリー
□投稿者/ エイン (1回)-(2011/08/13(Sat) 12:49:57)
LEFT JOINとINNER JOINの順番を変えたり、括弧で結合順位を明示してみるとどうですか?

それよりも、いくつか気になる点があります。
■AのクエリはGroup Byは要らないのでは?
■Bのクエリは無駄なことをしていませんか?
 ・SELECT 〜 FROM (SELECT 〜)なんてせずに、SELECT 〜 FROM テーブル名(以降、JOINが続く)でいいのでは?
 ・ 商品マスターを外部結合(LEFT JOIN)していますが、結合条件にない項目をWHERE句で使用している
  (LEFT(SHO.Bun,2) = '01')ので、これはINNER JOINでいいのでは?
引用返信 編集キー/
■61445 / inTopicNo.3)  Re[2]: 3つのテーブルを結合すると極端に遅くなるクエリー
□投稿者/ えれこぜ (2回)-(2011/08/13(Sat) 13:52:38)
No61443 (エイン さん) に返信

返信ありがとうございます。

> LEFT JOINとINNER JOINの順番を変えたり、括弧で結合順位を明示してみるとどうですか?

順番を変えたことによる変化はありませんでした。

> それよりも、いくつか気になる点があります。
> ■AのクエリはGroup Byは要らないのでは?

DISTINCT を使用した方が良いという事でしょうか。

SELECT DISTINCT
TBL.Ymd as Ymd
FROM PosTranData AS TBL
WHERE 1=1
AND TBL.Ymd BETWEEN '20110701' AND '20110731'

こちらも実行プランは変わらないようでした。しかし、
集計をすると利用できるインデックスも利かなくなるなどの弊害があるのでしょうか?

> ■Bのクエリは無駄なことをしていませんか?
>  ・SELECT 〜 FROM (SELECT 〜)なんてせずに、SELECT 〜 FROM テーブル名(以降、JOINが続く)でいいのでは?

Ymd,Ten,Pos,Receiptでブレイクして客数をカウントしたかったのですが、
もっと簡潔に書けると思いつつも、まだ良い記述方法が見つかっていません。試行してみます。

>  ・ 商品マスターを外部結合(LEFT JOIN)していますが、結合条件にない項目をWHERE句で使用している
>   (LEFT(SHO.Bun,2) = '01')ので、これはINNER JOINでいいのでは?

ありがとうございます。
完全にこの外部結合が余分な行数を読ませている原因でした。内部結合にしたところ、単体でも

B:部分実績 3864887行(T明細) → 31行 4秒(変更前:33秒)

となり、全体でも10秒(変更前:273秒)に短縮されました。

以前、考えなしに内部結合を行い集計漏れを発生させることが多かった為か、安易に外部結合を使用してしまったようです。
むしろ、内部結合を甘くみていたようです。考え直す機会を与えて頂き、ありがとうございました。
解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -