マンガでよめる痔のこと・薬のこと

SQLでVIEWを作成し、そのVIEWに対してSELECT文を書くときに、そのVIEWに対してWHERE句をつけるのは、パフォーマンスを必ず下げることになるのでしょうか?勝手な認識ですが、VIEWにWHERE句をつけると遅くなる場合があると聞きました。VIEWの組み方にももちろんよると思いますが、VIEWは消極的に使い、出来る限りJOINなどして結合したSQLを書くほうが無難なのでしょうか?よろしくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (4件)

例えば、



create view vw1 as select * from table1 where KeyCol2 = '1'

select * from vw1 where keyCol1 = 'X'
order by keyCol2
なんてすると、
select * from table1 where keyCol1 = 'X' and Keycol2 = '1'
order by keyCol3
はインデックス(KeyCol1,KeyCol2,KeyCol3)を使えるのに、
Viewを使ったほうが、インデックスを使えない
(KeyCol2が'1'を抽出してからkeyCol1='X'を洗い出すため)
なんてことが起きるかもしれません。
(この例は、SQLを解析した結果で実行計画が同じ処理となるかもしれませんが。)

なお、
SQLでVIEWを作成し、そのVIEWに対してSELECT文を書くときに、そのVIEWに対してWHERE句をつけるのは、パフォーマンスを必ず下げることになるのでしょうか?
は必ずしも下げることになるとは限りません。
where句でインデッックスを使えない場合、
Create view vw2
select * from table1 where NotIndexCol1 = 'A'
として、
select * from vw2 where NotIndexCol2 < 15
としようが、
select * from vw2 where NotIndexCol1 = 'A' and NotIndexCol2 < 15
としようがあまり変わらないはずです。
(SQL解析時間が少し早くなるかもしれませんが、体感速度の差というレベルではないはず。)

まあ、そもそも、View でwhere 句を書いて、Viewを使ったSelect句でも、where 句を書くのは
お薦めしません。(Viewが副問い合わせ扱いされる危険性があるため)
create view vw1
select * from table1 where NotIndexCol1 = '1'
して、
selcet vw1 where IndexCol1 = 12
なんてしたときに、table1 が10万件合って、IndexCol1 = 12 が10件しかなかったら
いったん、
select * from table1 where NotIndexCol1 = '1'
で数万件のワークを作って、その中からIndexCol1 = 12を探すという動きになったら
きわめて遅いだけです。(SQL解析能力に期待しましょう・・・というわけにはいかないので。)
こうなったら、
select * from table1 where IndexCol1 = 12 and NotIndexCol1 = '1'
としたほうがはるかに早い。
    • good
    • 0

>確認で申し訳ありませんが、結局、VIEWに対してWHERE句をつけても、相当複雑や件数が多い(10万件以上くらい)VIEWでない限り、パフォーマンスが落ちことは早々ないと考えてよろしいでしょうか?よろしくお願いいたします。



 そう考えて良いと思います。
    • good
    • 2

あくまでも個人的な意見ですが。

VIEWを多用すると、後でロジックを解析する場合に、解析が面倒になるので、あまり使わない方が良いと考えます。ただし、便利な場合もあります、私の作っている開発支援ツールは7種類のRDBMSで動くようになっていますが、テーブル一覧等を検索したい場合は、RDBMS毎にテーブル構造が大きく異なっているので、VIEWを使って同じ構造に見せかける事でツール側のSQLを同じに出来るようにしています。
    • good
    • 0
この回答へのお礼

回答、誠にありがとうございます。
なるほど、確かにそのような複数のミドルウェアで動かす場合、大変発揮するVIEWですね。一つ勉強になりました。

お礼日時:2013/02/12 23:42

 効率を気にする時には、まず、ちゃんと動く、且つ、読みやすくメンテナンスしやすいコードを書く事が先決です。


 プログラミングしてデバッグして運用する。運用しているうちに必ず手直しや改造が発生し、その時に再び、その書いたコードを読んで理解してから修正し、またデバッグする。
 このライフサイクル全体を見れば、読むに堪えない、複雑なSQLで、体感できないくらいの実行速度のアップを図るのと、使える物は何でも使って、とにかく見やすいSQLを組むのと、どちらが「総合的な」効率が良いかというと、間違いなく後者です。
 そぉ言う意味では、Viewは積極的に使う価値のあるツールだと思います。
 (近年、オプティマイザの性能もずいぶんよくなりました。DBMSは必要とあらば、自分で勝手にViewを展開してでも、実行順序をコントロールします。)

 ただし、Viewを使用したSQLを作った時に、どうしても、実行速度が実用にならないと判断された時は別です。
 まぁ、たいていは、インデックスや、下手するとテーブル設計がまずいことが速度低下の原因であることが多いですが、Viewが犯人だと確定したら、その時に、初めて、Viewを使わないでSQLを構築することを考えるのが筋ですね。
 こうすれば、Viewが必ず効率を下げるかとか言う議論はある意味、無意味です。

 いわゆる「効率化」とか「最適化」というのは細心の注意と測定結果をもとに、課題に応じて計画的にやるもので、原則に従って機械的に適用するものではありません。
    • good
    • 0
この回答へのお礼

回答、誠にありがとうございます。
おっしゃるとおり、確かに体感速度を感じない速度向上を気にするより、後で見た時に分かり良いSQLであることが大変重要であることは、私も経験上ございます。
積極的に使うことについては、個人的な考えにより、様々なご意見はございますが、いろいろなケースで試して行きたいと思います。
確認で申し訳ありませんが、結局、VIEWに対してWHERE句をつけても、相当複雑や件数が多い(10万件以上くらい)VIEWでない限り、パフォーマンスが落ちことは早々ないと考えてよろしいでしょうか?よろしくお願いいたします。

お礼日時:2013/02/12 23:52

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています

関連するカテゴリからQ&Aを探す

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QVIEWの元のテーブルのindexって有効なのでしょうか?

VIEWの元のテーブルのindexって有効なのでしょうか?
MYSQLサーバのバージョンは5.0.77です。
どうぞよろしくお願いします。

Aベストアンサー

ビューの基表に、有効活用できるインデクスがあれば、インデクスは活用されます。

>例えば元のテーブルに「hoge_id(index)」があり、
>VIEWテーブルが「vtable」だとします。

>SELECT * FROM vtable WHERE hoge_id = 値
>または、
>SELECT * FROM vtable LEFT JOIN atable ON vatble.hoge_id = atable.id
>(atable.idもindex)

>などとした場合、hoge_idのindexが有効で高速に結果が返ってくるということでよろしいのでしょうか。

表の母体データ件数が相当に少ない(例えば、数百件など)とか、重複キー値が多量に存在するといった場合は、RDBMSのオプティマイザが、「インデクスを使うより、テーブルスキャン(表のデータを全件サーチ)した方が速い」と判断し、インデクスを利用しない場合もあります。

主キーなどユニークなキーでの「=」条件や範囲条件などで、母体データからある程度絞り込んだ検索をするなら、インデクスの活用で母体データが大量に増えても、一定の性能を出せます。

ビューの基表に、有効活用できるインデクスがあれば、インデクスは活用されます。

>例えば元のテーブルに「hoge_id(index)」があり、
>VIEWテーブルが「vtable」だとします。

>SELECT * FROM vtable WHERE hoge_id = 値
>または、
>SELECT * FROM vtable LEFT JOIN atable ON vatble.hoge_id = atable.id
>(atable.idもindex)

>などとした場合、hoge_idのindexが有効で高速に結果が返ってくるということでよろしいのでしょうか。

表の母体データ件数が相当に少ない(例えば、数百件など)とか、重複キー値...続きを読む

QViewにインデックスは張れますか?

件名の通りなのですが、作成したViewが遅くて困っています。
改善方法としてはViewを作成しないで従来のSQLにインデックスを張って取得する方法にしようかなと考えています。
なにかいい方法はありますか?

Aベストアンサー

Viewの元テーブルに適切なIndexを貼る、ではいけないのですか?

Qビュー定義をプログラムで動的に扱う方法

ビュー定義をプログラムで動的に扱う方法
SQLServer2008+VB6(ExcelVBA)構成のシステムで、日付フィールドを含むテーブルのビューを作成しておき、VBプログラムからSQL文でビューを呼び出す時、日付範囲を指定して絞り込まれた結果をビューで返したいのですが、ストアドを使わずにビューだけで実現することはできないでしょうか?

Aベストアンサー

#2です。

>Set Cmd = New ADODB.Command
>Cmd.CommandText = ”CREATE VIEW ビュー AS SELECT * FROM テーブル WHERE 日付='2010/07/09'”
>Cmd.Execute

もちろん、権限があればできます。

しかし、そのリクエストをした人にもう一度確認することをお勧めします。
私もVB内で10行以上のクエリを組み立てて実行しているのを見てげっそりすることはありますので、
「長いクエリはビューで管理したい」というリクエストは理解できます。

ただ、本当に「パラメータまで含めて一切をビューにし、すべてWHERE文の一切ないSELECT * FROM ビューだけにしたい」
というリクエストをしたとすれば、その人はシステムのことを理解していないので、説明すべきだと思います。

・同時に複数のユーザ・複数の処理でビューを参照できなくなるので、ユーザ数×処理数だけ同じようなビューが必要
・ビュー定義の一部だけを再作成することはできないので、再作成には常に全部を実行する必要がある。処理はわかりやすくならない

#2です。

>Set Cmd = New ADODB.Command
>Cmd.CommandText = ”CREATE VIEW ビュー AS SELECT * FROM テーブル WHERE 日付='2010/07/09'”
>Cmd.Execute

もちろん、権限があればできます。

しかし、そのリクエストをした人にもう一度確認することをお勧めします。
私もVB内で10行以上のクエリを組み立てて実行しているのを見てげっそりすることはありますので、
「長いクエリはビューで管理したい」というリクエストは理解できます。

ただ、本当に「パラメータまで含めて一切をビューにし、すべてWHERE文の一切...続きを読む

Q3つの表の外部結合

表A、B、Cの3つがあり、Aのすべての行を出力したいと考えています。
外部結合を用いるのだとは思うのですが、3つの表に対して行う場合の
書き方がわからず困っています。
ご教授いただけないでしょうか?
select * from a,b,c
where a.商品ID =b.商品ID (+) and b.商品ID (+) =c.商品ID (+)
としてみましたが、うまくいきませんでした。

Aベストアンサー

ansi構文の趣旨からいえば、結合条件と絞り込み条件は分けて書くので・・

select *
from a
left join b on (a.商品ID =b.商品ID)
left join c on (b.商品ID =c.商品ID)
where a.年月 = 任意の値

と書くのが一般的でしょうね。

QERROR1062:Duplicate entry.....というエラーが出てしまいました

いつもお世話になります。
データベースからSELECTで抽出したデータを別のテーブルにINSERTするSQLを実行したのですが、
ERROR1062:Duplicate entry.....というエラーが出てしまいました。
お詳しい方がいらっしゃいましたら、アドバイスをいただけませんでしょうか?よろしくお願いいたします。
【実行したSQL】
INSERT INTO tblA (dataA1, dataA2, dataA3, dataA4) SELECT "9001","AA",dataB1,dataB2 FROM tblB WHERE dataB1 = 52

tblAの主キー:dataA1とdataA2
tblBの主キー:dataB1

dataA1とdataA2はtblAの主キーとなっているため、重複してしまうということのようです。tblBの主キーはdataB1であるため、抽出されてくるデータは常に1件なので問題ないと期待していましたが、甘くなかったようです。何か良い方法はないものでしょうか?よろしくお願いいたします。

Aベストアンサー

「ERROR 1062」は、重複データを格納しようとした場合に出力されるエラーです。
既にdataA1='9001'&dataA2='AA'という行が、tblAに格納されているのですよね?

>抽出されてくるデータは常に1件なので問題ないと期待していました

「insert ~ select ~」を実行前に、既に同じデータが格納されているのでは?
あるいはprimary keyの指定が、質問中に記された通りでなく、2件以上検索されているかです。

>何か良い方法はないものでしょうか?

何をするための方法を、聞きたいのかが分かりませんが?

QMySQLで改行を含む文の登録のしかた(改行コード

MySQLで改行を含む文を登録したいんですが、改行を改行コードに書き換えて登録したいです。
改行コードはどのように書けばいいですか?

登録したい文:
あいうえお
かきくけこ
さしすせそ

Aベストアンサー

改行コードは¥nで登録すれば良いです。

Qビューで引数を使いたい

4つのテーブルのいずれかをアクセスしますが、
select文はひとつでwhereでテーブルを指定したいので、
 例:select * from ビュー where table_no=1
とかで、table_noの値でアクセスするビューは
作れますか?
※この例の場合、select * from table1が実行したい。

4つのテーブルは全て同じ構造で、
データが違うのみです。

Aベストアンサー

ビューでは不可能だと思います。

同じ様なアクセス方法を行いたいのであれば、
テーブル値を返すユーザー定義関数を作成する方法があるかと思います。構造は同じと言う事なので、1つの関数で済むと思いますし。

例:Select * From ユーザー定義関数(1~4のパラメータ)

上記例の様な使い方が可能です。

QMAX値を条件にデータを取得するには?

SQL文で困っています。
ご教授下さい。


下記のようなデータがあった場合、それぞれの区分毎に
年月が最大(最新)のデータを取得したいです。
(実際には1レコードにその他項目があり、それらも取得します。)
<検索対象データ>
区分 年月   金額
-----------------------------
A   200412  600
A   200503  560
B   200311  600
B   200508  1000
B   200504  560
C   200508  400
C   200301  1100


<取得したいデータ>

区分 年月   金額
-----------------------------
A   200503  560
B   200508  1000
C   200508  400

よろしくお願いします。

Aベストアンサー

テーブル名をXXXとすると次のようなSQLでよいと思います。(最善の方法かどうかは自信がないですが)

select B.* from (select 区分, max(年月) as 年月 from XXX group by 区分) As A
inner join XXX as B on A.区分 = B.区分 and A.年月 = B.年月
order by B.区分

Qレスポンスをよくするには?

こんにちは。
最近ずっと仕事でシステムのレスポンスの改善を行っています。
ログをとり、VIEWが遅いのはわかりました。
INDEXを貼ってみたりヒント文を使ってみたりしたのですが、
なかなか早くなりません。
コストが現在2693あります。
これを100未満にしたいのですが・・・
使っているテーブルは2つあり、
両方ともデータ件数は100万件ほどあります。
それぐらいの件数になると、コストはどうしても増えてしまうのでしょうか?

こうしたら早くなるのでは?等の
案があったら教えてください、お願いします。

VIEWの中のSQL部
SELECT TP.STATUS , TP.DENPYO_NO, TP.EDABAN, JH.USER_ID
FROM (SELECT P.DENPYO_NO, P.EDABAN, P.STATUS FROM TBL_CHOHYO_KANRI P WHERE P.HAKO_KBN = '99') TP
,(SELECT J.DENPYO_NO, J.EDABAN FROM TBL_DENPYO_RIREKI J) JH
WHERE JH.DENPYO_NO = TP.DENPYO_NO AND JH.EDABAN = TP.EDABAN
;

実行計画
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=2693 Card=33854 By
tes=1117182)

1 0 HASH JOIN (Cost=2693 Card=33854 Bytes=1117182)
2 1 TABLE ACCESS (FULL) OF 'TBL_CHOHYO_KANRI' (TABLE) (Cost=2
027 Card=127611 Bytes=2424609)

3 1 INDEX (FAST FULL SCAN) OF 'IDX$$_2CCE0006' (INDEX) (Cost
=157 Card=203124 Bytes=2843736)

統計
----------------------------------------------------------
11 recursive calls
0 db block gets
9812 consistent gets
11039 physical reads
0 redo size
7925659 bytes sent via SQL*Net to client
147915 bytes received via SQL*Net from client
13403 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
201021 rows processed

こんにちは。
最近ずっと仕事でシステムのレスポンスの改善を行っています。
ログをとり、VIEWが遅いのはわかりました。
INDEXを貼ってみたりヒント文を使ってみたりしたのですが、
なかなか早くなりません。
コストが現在2693あります。
これを100未満にしたいのですが・・・
使っているテーブルは2つあり、
両方ともデータ件数は100万件ほどあります。
それぐらいの件数になると、コストはどうしても増えてしまうのでしょうか?

こうしたら早くなるのでは?等の
案があったら教えてください、お願...続きを読む

Aベストアンサー

ORACLE方言を使わずに ANSIで書くとこういうことでしょうか?
「USER_IDを TBL_CHOHYO_KANRIに付与したい」ということでしょうか?

SELECT
 P.STATUS
 ,P.DENPYO_NO
 ,P.EDABAN
 ,J.USER_ID
FROM TBL_CHOHYO_KANRI P
  INNER JOIN TBL_DENPYO_RIREKI JH ON ( J.DENPYO_NO = P.DENPYO_NO
                  AND J.EDABAN  = P.EDABAN   )
WHERE P.HAKO_KBN = '99'

そうだとすると、質問文から読み取れる範囲での性能対策は
・テーブル結合用の索引として、各テーブルにDENPYO_NO,EDABANに索引をはる
・定数を指定しているHAKO_KBNに索引
・DENPYO_NO,EDABANとHAKO_KBNの索引を同じにするかどうか実行結果を取って比べてみる
ということくらいしか回答できません。

コストを下げるには、検索で使用するレコード母数を少なくする必要があると思います。「テーブルにデータをいれておかない」ということです。

レコード数の多いテーブル同士の結合ではなおさらのことなので、このSQLが走る前に何らかの方法でワークテーブルをつくっておいて、そのテーブルを検索するということはできませんか?

ORACLE方言を使わずに ANSIで書くとこういうことでしょうか?
「USER_IDを TBL_CHOHYO_KANRIに付与したい」ということでしょうか?

SELECT
 P.STATUS
 ,P.DENPYO_NO
 ,P.EDABAN
 ,J.USER_ID
FROM TBL_CHOHYO_KANRI P
  INNER JOIN TBL_DENPYO_RIREKI JH ON ( J.DENPYO_NO = P.DENPYO_NO
                  AND J.EDABAN  = P.EDABAN   )
WHERE P.HAKO_KBN = '99'

そうだとすると、質問文から読み取れる範囲での性能対策は
・テーブル結合用の索引として、各テーブ...続きを読む

QInner join と Left joinの明確な違いは?

Inner join と Left joinの違いがよくわかりません。
教えてください。

Aベストアンサー

出てくる結果が違います。

テーブル1のフィールド1に、






が、

テーブル2のフィールド1に、






が入力されている場合、

SELECT [テーブル1].[フィールド1], [テーブル2].[フィールド1]
FROM テーブル1 LEFT JOIN テーブル2 ON [テーブル1].[フィールド1]=[テーブル2].[フィールド1];
では、結果は、
テーブル1.フィールド1 テーブル2.フィールド1
1               1
2               2
3               3
4               NULL
5               NULL
6               NULL
の6レコードが出力されますが、

SELECT [テーブル1].[フィールド1], [テーブル2].[フィールド1]
FROM テーブル1 INNER JOIN テーブル2 ON [テーブル1].[フィールド1]=[テーブル2].[フィールド1];
では、結果は、
テーブル1.フィールド1 テーブル2.フィールド1
1               1
2               2
3               3
の3レコードしか出力されません。

出てくる結果が違います。

テーブル1のフィールド1に、






が、

テーブル2のフィールド1に、






が入力されている場合、

SELECT [テーブル1].[フィールド1], [テーブル2].[フィールド1]
FROM テーブル1 LEFT JOIN テーブル2 ON [テーブル1].[フィールド1]=[テーブル2].[フィールド1];
では、結果は、
テーブル1.フィールド1 テーブル2.フィールド1
1               1
2               2
3           ...続きを読む


このQ&Aを見た人がよく見るQ&A

人気Q&Aランキング