- PR -

SQLのINNER JOIN で速くする方法を教えて下さい

1
投稿者投稿内容
うしぇ
会議室デビュー日: 2006/04/25
投稿数: 6
投稿日時: 2006-07-07 12:01
SQLServer2000

作成したビューがとても遅くて困っています。
どうか、知恵を貸してください。

ビューの内容としては
・本人用ビュー(本人用テーブルと本人情報テーブルが結合されている)
 内容:本人ID・本人氏名など
件数:10万レコードくらい
・家族用ビュー(家族用テーブルと家族情報テーブルが結合されている)
 内容:家族ID・家族氏名など
件数:20万レコードくらい
・調査用テーブル
 内容:本人ID・家族ID1〜6など
件数:1000レコードくらい
の3つを結合しています。

ただし、調査用テーブルについては
本人・家族1・家族2・家族3・家族4・家族5・家族6
が1レコードとなっています。

この調査用テーブルを
本人・家族1
本人・家族2
  …
本人・家族6のように6分割して6つのレコードにしたいのです。
さらに本人と家族の情報も結合したいのです。

考えたのが
SELECT 本人ID・家族1ID…
FROM
((SELECT 本人ID・家族1ID… FROM 調査用テーブル)
 UNION ALL
 (SELECT 本人ID・家族2ID… FROM 調査用テーブル)
 UNION ALL
 (SELECT 本人ID・家族3ID… FROM 調査用テーブル)
 UNION ALL
 (SELECT 本人ID・家族4ID… FROM 調査用テーブル)
 UNION ALL
 (SELECT 本人ID・家族5ID… FROM 調査用テーブル)
 UNION ALL
 (SELECT 本人ID・家族6ID… FROM 調査用テーブル) ) AS 調査TBL
INNER JOIN 家族用ビュー
ON 調査TBL.家族ID=家族用ビュー.家族ID
INNER JOIN 本人用ビュー
ON 調査TBL.本人ID=本人用ビュー.本人ID

としました。
調査用テーブル・本人用ビュー・家族用ビューはそれぞれ全指定(SELECT * FROM テーブル名)とすると
1秒くらいで表示されます。
なのに、この結合をすると全指定で30秒くらいかかります。
もっと速くするには、どうしたら良いのでしょうか?
よろしくお願いします。
あしゅ
ぬし
会議室デビュー日: 2005/08/05
投稿数: 613
投稿日時: 2006-07-07 12:14
引用:

うしぇさんの書き込み (2006-07-07 12:01) より:
ただし、調査用テーブルについては
本人・家族1・家族2・家族3・家族4・家族5・家族6
が1レコードとなっています。


第一正規形にすらなっていない構造だからです。
それなりに正規化するだけで桁違いに速くなると思いますよ。
うしぇ
会議室デビュー日: 2006/04/25
投稿数: 6
投稿日時: 2006-07-07 13:06
早い返答ありがとうございます。
正規化というのが、少々わかっていないかもしれませんが、

本人・家族1・家族2・家族3・家族4・家族5・家族6
の1テーブルを
本人・家族1
UNION ALL
本人・家族2
UNION ALL
  …
本人・家族6
としているのですが、正規化にはならないのでしょうか?
またビューでは無理ということでしょうか?
めだか
大ベテラン
会議室デビュー日: 2004/11/11
投稿数: 109
投稿日時: 2006-07-07 13:08
UNIONした結果にINNER JOINするのではなくて

家族1とINNER JOIN
家族2とINNER JOIN・・・・・
したものをUNIONすれば速くなったりしませんか?
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2006-07-07 13:30
引用:

うしぇさんの書き込み (2006-07-07 13:06) より:
としているのですが、正規化にはならないのでしょうか?


なりません。正規化というのはデータベースのテーブル設計の段階で行うプロセスです。あなたの行っている行為は設計段階のまずさを、実装段階でごまかそうとしているわけです。
うしぇ
会議室デビュー日: 2006/04/25
投稿数: 6
投稿日時: 2006-07-07 13:51
みなさん回答ありがとうございます。

>めだかさん
それぞれにINNER JOINしてみたのですが、さらに遅くなってしまいました。

>甕星
テーブルの設計に問題ありということなのですね。
正規化についての回答ありがとうございます。
JIMMY
常連さん
会議室デビュー日: 2004/10/26
投稿数: 32
お住まい・勤務地: 東京
投稿日時: 2006-07-07 21:41
こんにちは

チョットだけ見させてもらいましたが、テーブル構造の正規化をすべきだという話題になってきたと思います。

うしぇさん的には「そんなことしたら他の処理全て影響が出ちゃう!」と言ったところでしょうが。
でも、テーブル構造を変更しないとこの先何をやってもパフォーマンスが悪くなることを考えると、必要なことだと思います。

で、例えば正規化の案ですが、私ならこう考える・・・です
(<>で囲んだ項目で主キーを編成)
【本人テーブル】
<本人ID>、本人氏名、・・・

【本人情報テーブル】(これが分ける必要のあるものか怪しい、常に1対1で本人テーブルと結合できるなら一つのテーブルのほうが望ましい場合が多いです)
<本人ID>、本人情報、・・・

【家族用テーブル】
<本人ID>、<家族NO>、家族氏名、・・・

【家族用テーブル】(本人情報テーブルと同様に、家族用テーブルにまとめることは出来ませんか?)
<本人ID>、<家族NO>、家族情報、・・・

【調査用テーブル】
<本人ID>、<家族NO>、調査情報、・・・・

本人については、暗黙の家族NOとしてゼロを付与、家族用テーブルに入るレコードの家族NOは1〜
こうすることによって
・家族が本人を含めて8人以上の家族でも管理できる
・調査用テーブルのレコードは1人分の情報しか持たないため、無駄なフィールドを持たなくて済む。(値の有無をいちいち確認する必要がなくなる)
というシステム的なメリットが出てきます。

また、本人用ビュー/家族用ビューは現状と同じ様に作ることが出来るでしょう。
現状の調査用テーブルをビューで実現することも可能かつ、今考えている機能は新しいテーブルを使った形で考えると

SELECT f.本人ID, u.本人氏名, f.家族NO, f.家族氏名, i.調査情報
FROM 家族用ビュー AS f
INNER JOIN 本人用ビュー as u ON f.本人ID = u.本人ID
INNER JOIN 調査用テーブル as i ON f.本人ID = i.本人ID AND f.家族NO = i.家族NO

で取得できるような気がします。(未検証、こんな感じで・・・程度に見てください)

いかがでしょうか?



[ メッセージ編集済み 編集者: JIMMY 編集日時 2006-07-07 21:43 ]
うしぇ
会議室デビュー日: 2006/04/25
投稿数: 6
投稿日時: 2006-07-10 11:09
JIMMYさん回答ありがとうございます。遅くなって申し訳ありません。

> 【本人テーブル】
> <本人ID>、本人氏名、・・・
>
> 【本人情報テーブル】(これが分ける必要のあるものか怪しい、常に1対1で本人テーブルと> 結合できるなら一つのテーブルのほうが望ましい場合が多いです)
> <本人ID>、本人情報、・・・
っとありますが、本人テーブルと本人情報テーブルは提供されたもので、最初から分かれていました。
・本人テーブルは本人の働いている所が変わったら1レコードずつ増えていく。(履歴が残る)
・本人情報テーブルは名前や住所が変わったら1レコードずつ増えていく。(履歴が残る)
となっているので1対1ではないのですが、SEQbェあるので最大で絞り込み、
リレーションして本人IDが1つになるようになっています。
ちなみに家族も同様です。

今回の本人用ビュー・家族用ビューはリレーションして繋げることも可能なのですが、
繋げた結果遅いということで廃止になってしまいました。
ちなみに家族がいない本人(一人身の人)はレコードの取得をしないです。

みなさん正規化について教えていただいたのですが、
テーブル構成は決まっているものを使用しているため変更が出来ないのです。

今出来ることはビューの変更・追加か、プログラムの修正です。
ビューが速くなればと思いましたが、テーブルの構成が悪いのであれば
どうしようもないのですね・・・

ありがとうございます。修正する日が近づいているので、修正したら報告します。
1

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