- PR -

JOIN句

投稿者投稿内容
ユウ
会議室デビュー日: 2007/05/14
投稿数: 4
投稿日時: 2007-05-14 15:24
こんにちわ。

既存のSQLの応答時間が遅いので、修正した所時間短縮されていなくて困っています。
JOINを使用しているのですが。。
UNIONを使用した方がいいのでしょうか?

<修正前>
SELECT PPL.使用数量1,
PPL.使用数量2,
PPL.使用数量3,
PPL.使用数量4,
PPL.使用数量5,
PPL.使用数量6,
PPL.使用数量7,
PPL.使用数量8,
PPL.使用数量9,
PPL.使用数量10,
PPL.使用数量11,
PPL.使用数量12,
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量1 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量2 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量3 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量4 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量5 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量6 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量7 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量8 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量9 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量10 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量11 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量12 END),
HNM.品名,
STJ.規格1,
STJ.規格2,
STJ.規格3,
STJ.規格4,
STJ.規格5,
SEM.枝番名称,
PPL.使用製品群在庫種別 AS 在庫種別,
STJ.材料基準単価,
KBH.区分名称,
STJ.フラフリターン率,
((CASE WHEN STJ.仕入区分 = '1' THEN '1' ELSE '0' END)
|| HNM.資材大分類コード || HNM.資材中分類コード || HNM.資材小分類コード) AS 品名分類,
STJ.グレード,
STJ.色番
FROM ( BCFPPLD PPL
LEFT OUTER JOIN BCMKBHD KBH ON
PPL.削除区分 = '0'
AND PPL.会社コード = '01'
AND PPL.年度 = '2007'
AND PPL.部署コード = '3240'
AND KBH.削除区分 = '0'
AND KBH.会社コード = PPL.会社コード
AND KBH.項目コード = '0070' )
, BCMSCMD TJM, BCMMTRD STJ, BCMHNMD HNM,BCMSGMD SGM,BCMSEMD SEM
WHERE PPL.削除区分 = '0'
AND PPL.会社コード = '01'
AND PPL.年度 = '2007'
AND PPL.部署コード = '3240'
AND TJM.削除区分 = '0'
AND TJM.会社コード = '01'
AND TJM.製造工場コード = (PPL.使用工場取引先コード || PPL.使用工場取引先口座コード)
AND TJM.製品群コード = PPL.使用製品群コード
AND TJM.製品群枝番 = PPL.使用製品群枝番
AND TJM.適用日付 <= '20070321'
AND TJM.有効日付 >= '20070321'
AND STJ.削除区分 = '0'
AND STJ.会社コード = '01'
AND STJ.製造工場コード = (PPL.使用工場取引先コード || PPL.使用工場取引先口座コード)
AND STJ.製品群コード = PPL.使用製品群コード
AND STJ.製品群枝番 = PPL.使用製品群枝番
AND STJ.適用日付 = TJM.適用日付
AND STJ.品名コード = PPL.製品群品名使用資材コード
AND HNM.品名コード = PPL.製品群品名使用資材コード
AND HNM.品名コード枝番 = '0'
AND HNM.削除区分 = '0'
AND SGM.会社コード = '01'
AND SGM.製品群コード = PPL.使用製品群コード
AND SGM.適用日付 <= '20070321'
AND SGM.有効日付 >= '20070321'
AND SGM.削除区分 = '0'
AND SEM.会社コード = '01'
AND SEM.製品群コード = PPL.使用製品群コード
AND SEM.適用日付 = SGM.適用日付
AND SEM.製品群枝番 = PPL.使用製品群枝番
AND SEM.削除区分 = '0'
AND KBH.区分コード = STJ.材料基準単価単位コード
ORDER BY 品名分類,PPL.製品群品名使用資材コード,
STJ.グレード,STJ.色番,STJ.規格1,STJ.規格2,STJ.規格3,STJ.規格4,STJ.規格5,
PPL.使用製品群コード,PPL.使用製品群枝番,在庫種別

<修正後>
SELECT DISTINCT
使用数量1, 使用数量2,
使用数量3, 使用数量4,
使用数量5, 使用数量6,
使用数量7, 使用数量8,
使用数量9, 使用数量10,
使用数量11, 使用数量12,
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量1 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量2 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量3 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量4 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量5 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量6 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量7 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量8 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量9 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量10 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量11 END),
(CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量12 END),
品名
FROM
BCFPPLD PPL LEFT JOIN (
SELECT
区分コード, 区分名称
FROM
BCMKBHD KBH
WHERE
会社コード='01' AND
削除区分='0' AND
項目コード = '0070' ) A ON PPL.会社コード = 会社コード LEFT JOIN (
SELECT
品名,品名コード,品名コード枝番,
資材大分類コード,資材中分類コード,
資材小分類コード
FROM
BCMHNMD HNM
WHERE
品名コード枝番 = '0' AND
削除区分='0') B ON PPL.製品群品名使用資材コード = 品名コード LEFT JOIN (
SELECT
製品群コード, 適用日付
FROM
BCMSGMD SGM
WHERE
会社コード = '01' AND
削除区分 = '0' ) C ON C.製品群コード = PPL.使用製品群コード LEFT JOIN (
SELECT
製品群コード, 適用日付,
製品群枝番, 枝番名称
FROM
BCMSEMD SEM
WHERE
会社コード = '01' AND
削除区分='0' ) D ON D.製品群コード = PPL.使用製品群コード
WHERE
PPL.削除区分 = '0' AND
PPL.会社コード = '01' AND
PPL.年度 = '2007' AND
PPL.部署コード = '3240'

まだ、途中なんですが、すべてのテーブルを結合した時点であまり応答時間が変わりませんでした。
どなたか教えていただけないでしょうか。
mso
ぬし
会議室デビュー日: 2003/12/04
投稿数: 496
お住まい・勤務地: 宮城
投稿日時: 2007-05-14 16:13
msoです。

引用:

ユウさんの書き込み (2007-05-14 15:24) より:

まだ、途中なんですが、すべてのテーブルを結合した時点であまり応答時間が変わりませんでした。
どなたか教えていただけないでしょうか。



長いので全部みていませんが、UNIONにしてもあまり変わらないと思います。
INDEXとかは適切に使われていますか?

ご確認ください。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2007-05-14 16:23
どんなRDBを使うかで全然チューニング方法違いますが、
その件について明記すべきでしょう。
でも、これだけ大きいSQLを貼り付けたところで読む気がしませんね。

まずは、お使いのRDBに実行プランを参照する方法があれば、それを使いましょう。
SQLのどの部分にコストが沢山かかっているかが分かります。
ユウ
会議室デビュー日: 2007/05/14
投稿数: 4
投稿日時: 2007-05-14 16:56
こんにちわ

素早い返信ありがとうございます。
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
MSOさんへ
−−−−−−−−−−−−−−−−−−−−−
>INDEXとかは適切に使われていますか?
−−−−−−−−−−−−−−−−−−−−−

修正前のSQLをもとにして、テーブルの構成を参照し、書いたのですが。
もう一度考え直します。
ありがとうございます。

−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

ぬしさんへ

もう一度、どの部分にコストがかかっているか検証し、
修正に取り組みます。
ありがとうございます。

環境は、OSがXP
DBソフトが富士通のsymfoware です。
明記していなくてすいません。
温州蜜柑
ベテラン
会議室デビュー日: 2005/01/24
投稿数: 65
お住まい・勤務地: 東京都
投稿日時: 2007-05-14 19:18
以前ORACLEでですが、WHEREの条件をFROM句にもってきたら遅い検索が
高速になったことがありました。
Symfoware でどうなるかまったくわかりませんが...

コード:
SELECT DISTINCT
    使用数量1, 使用数量2,
    使用数量3, 使用数量4,
    使用数量5, 使用数量6,
    使用数量7, 使用数量8,
    使用数量9, 使用数量10,
    使用数量11, 使用数量12,
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量1 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量2 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量3 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量4 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量5 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量6 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量7 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量8 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量9 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量10 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量11 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量12 END),
    品名
FROM
    (
        SELECT
            '01' AS 会社コード,
            '2007' AS 年度,
            '0' AS 削除区分,
            '3240' AS 部署コード
        FROM
            RDBII_SYSTEM.RDBII_ASSISTTABLE -- ORACLE の DUAL 相当らしい
    ) X LEFT JOIN BCFPPLD PPL ON (
        X.会社コード = PPL.会社コード AND 
        X.年度 = PPL.年度 AND 
        X.削除区分 = PPL.削除区分 AND 
        X.部署コード = PPL.部署コード ) LEFT JOIN (
    (
        SELECT
            区分コード, 区分名称
        FROM
            BCMKBHD KBH
        WHERE
            会社コード='01' AND
            削除区分='0' AND
            項目コード = '0070'
    ) A ON PPL.会社コード = 会社コード LEFT JOIN
    (
        SELECT
            品名,品名コード,品名コード枝番,
            資材大分類コード,資材中分類コード,
            資材小分類コード
        FROM
            BCMHNMD HNM
        WHERE
            品名コード枝番 = '0' AND
            削除区分='0'
    ) B ON PPL.製品群品名使用資材コード = 品名コード LEFT JOIN
    (
        SELECT
            製品群コード, 適用日付
        FROM
            BCMSGMD SGM
        WHERE
            会社コード = '01' AND
            削除区分 = '0' 
    ) C ON C.製品群コード = PPL.使用製品群コード LEFT JOIN
    (
        /* ここで枝番まで検索する必要がある? distinct 製品群コード だけでいいのでは? */
        SELECT
            製品群コード, 適用日付,
            製品群枝番, 枝番名称
        FROM
            BCMSEMD SEM
        WHERE
            会社コード = '01' AND
            削除区分='0'
    ) D ON D.製品群コード = PPL.使用製品群コード
--WHERE
--  PPL.削除区分 = '0' AND
--  PPL.会社コード = '01' AND
--  PPL.年度 = '2007' AND
--  PPL.部署コード = '3240' 


ユウ
会議室デビュー日: 2007/05/14
投稿数: 4
投稿日時: 2007-05-15 09:04
温州蜜柑さんへ

返事おそくなりすいません。

dual句を使用するということは気がつきませんでした。
一行一列のダミーテーブルとして使用の場合は有効なんですかね。
symfoで使用できるとは知りませんでした。

上記を参考にし、もう一度組みなおして作業します。

ありがとうございました。
eternia
常連さん
会議室デビュー日: 2006/02/23
投稿数: 42
投稿日時: 2007-05-15 10:59
#質問の回答ではないです。

symfoware使ったこと無いので違ってたらすいません。
修正前と修正後で結合条件が変わっている気がするんですが大丈夫でしょうか?
(上は内部結合、下は外部結合)

直すとこうなるのかな?(動作確認はしていないです)

SELECT PPL.使用数量1,
PPL.使用数量2,
PPL.使用数量3,
PPL.使用数量4,
PPL.使用数量5,
PPL.使用数量6,
PPL.使用数量7,
PPL.使用数量8,
PPL.使用数量9,
PPL.使用数量10,
PPL.使用数量11,
PPL.使用数量12,
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量1 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量2 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量3 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量4 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量5 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量6 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量7 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量8 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量9 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量10 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量11 END),
(CASE WHEN KBH.区分コード = '05' THEN 0 ELSE PPL.使用重量12 END),
HNM.品名,
STJ.規格1,
STJ.規格2,
STJ.規格3,
STJ.規格4,
STJ.規格5,
SEM.枝番名称,
PPL.使用製品群在庫種別 AS 在庫種別,
STJ.材料基準単価,
KBH.区分名称,
STJ.フラフリターン率,
((CASE WHEN STJ.仕入区分 = '1' THEN '1' ELSE '0' END)
|| HNM.資材大分類コード || HNM.資材中分類コード || HNM.資材小分類コード) AS 品名分類,
STJ.グレード,
STJ.色番
FROM ( BCFPPLD PPL
LEFT OUTER JOIN BCMKBHD KBH ON KBH.会社コード = PPL.会社コード
AND KBH.区分コード = STJ.材料基準単価単位コード
)
inner join BCMSCMD TJM on TJM.製造工場コード = (PPL.使用工場取引先コード || PPL.使用工場取引先口座コード)
AND TJM.製品群コード = PPL.使用製品群コード
AND TJM.製品群枝番 = PPL.使用製品群枝番
inner join BCMMTRD STJ on STJ.製造工場コード = (PPL.使用工場取引先コード || PPL.使用工場取引先口座コード)
AND STJ.製品群コード = PPL.使用製品群コード
AND STJ.製品群枝番 = PPL.使用製品群枝番
AND STJ.適用日付 = TJM.適用日付
AND STJ.品名コード = PPL.製品群品名使用資材コード
inner join BCMHNMD HNM on HNM.品名コード = PPL.製品群品名使用資材コード
inner join BCMSGMD SGM on SGM.製品群コード = PPL.使用製品群コード
inner join BCMSEMD SEM on SEM.製品群コード = PPL.使用製品群コード
AND SEM.適用日付 = SGM.適用日付
AND SEM.製品群枝番 = PPL.使用製品群枝番
WHERE
PPL.削除区分 = '0'
AND PPL.会社コード = '01'
AND PPL.年度 = '2007'
AND PPL.部署コード = '3240'
AND KBH.削除区分 = '0'
AND KBH.項目コード = '0070'
PPL.削除区分 = '0'
AND TJM.削除区分 = '0'
AND TJM.会社コード = '01'
AND TJM.適用日付 <= '20070321'
AND TJM.有効日付 >= '20070321'
AND STJ.削除区分 = '0'
AND STJ.会社コード = '01'
AND HNM.品名コード枝番 = '0'
AND HNM.削除区分 = '0'
AND SGM.会社コード = '01'
AND SGM.適用日付 <= '20070321'
AND SGM.有効日付 >= '20070321'
AND SGM.削除区分 = '0'
AND SEM.会社コード = '01'
AND SEM.削除区分 = '0'
ORDER BY 品名分類,PPL.製品群品名使用資材コード,
STJ.グレード,STJ.色番,STJ.規格1,STJ.規格2,STJ.規格3,STJ.規格4,STJ.規格5,
PPL.使用製品群コード,PPL.使用製品群枝番,在庫種別
温州蜜柑
ベテラン
会議室デビュー日: 2005/01/24
投稿数: 65
お住まい・勤務地: 東京都
投稿日時: 2007-05-15 13:37
引用:

ユウさんの書き込み (2007-05-15 09:04) より:
温州蜜柑さんへ

返事おそくなりすいません。

dual句を使用するということは気がつきませんでした。
一行一列のダミーテーブルとして使用の場合は有効なんですかね。
symfoで使用できるとは知りませんでした。

上記を参考にし、もう一度組みなおして作業します。

ありがとうございました。




ちょっとひらめきました。
各種マスタで「 削除区分 = '0' 」という条件があるのがガンなのではないでしょうか?
「case when ... 」を使用して以下のようにしたらいかがでしょう?
※ eterniaさんが指摘しているように、「修正前」と「修正後」のクエリが
  ちがっていますね?
  とりあえず、「修正後」のクエリを私なりに改造してみました。

コード:
SELECT DISTINCT
    使用数量1, 使用数量2,使用数量3, 使用数量4,
    使用数量5, 使用数量6,使用数量7, 使用数量8,
    使用数量9, 使用数量10,使用数量11, 使用数量12,
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量1 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量2 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量3 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量4 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量5 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量6 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量7 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量8 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量9 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量10 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量11 END),
    (CASE WHEN 区分コード = '05' THEN 0 ELSE 使用重量12 END),
    品名
FROM
    BCFPPLD PPL
    INNER JOIN (
        SELECT
            case when 削除区分 = '0' then 区分コード else null end as 区分コード,
            case when 削除区分 = '0' then 区分名称   else null end as 区分名称
        FROM
            BCMKBHD KBH
        WHERE
            会社コード = '01' AND
            項目コード = '0070' 
    ) A ON PPL.会社コード = 会社コード
    INNER JOIN (
        SELECT
            case when 削除区分 = '0' then 品名             else null end as 品名            ,
            case when 削除区分 = '0' then 品名コード       else null end as 品名コード      ,
            case when 削除区分 = '0' then 品名コード枝番   else null end as 品名コード枝番  ,
            case when 削除区分 = '0' then 資材大分類コード else null end as 資材大分類コード,
            case when 削除区分 = '0' then 資材中分類コード else null end as 資材中分類コード,
            case when 削除区分 = '0' then 資材小分類コード else null end as 資材小分類コード
        FROM
            BCMHNMD HNM
        WHERE
            品名コード枝番 = '0'
    ) B ON PPL.製品群品名使用資材コード = 品名コード
    INNER JOIN (
        SELECT
            case when 削除区分 = '0' then 製品群コード else null end as 製品群コード,
            case when 削除区分 = '0' then 適用日付     else null end as 適用日付
        FROM
            BCMSGMD SGM
        WHERE
            会社コード = '01'
    ) C ON PPL.使用製品群コード = C.製品群コード
    INNER JOIN (
        SELECT
            case when 削除区分 = '0' then 製品群コード else null end as 製品群コード,
            case when 削除区分 = '0' then 適用日付     else null end as 適用日付    ,
            case when 削除区分 = '0' then 製品群枝番   else null end as 製品群枝番  ,
            case when 削除区分 = '0' then 枝番名称     else null end as 枝番名称
        FROM
            BCMSEMD SEM
        WHERE
            会社コード = '01'
    ) D ON PPL.使用製品群コード = D.製品群コード
WHERE
    PPL.削除区分 = '0' AND
    PPL.会社コード = '01' AND
    PPL.年度 = '2007' AND
    PPL.部署コード = '3240'


スキルアップ/キャリアアップ(JOB@IT)