• 締切済み

以下のようなSQLについて教えてください。

売上トランと商品マスタがあるとします。 商品マスタは廃止フラグをVARCHAR2(1)で保持していて、 1なら廃止、0なら今販売中で、 商品マスタは全件で100万件あり、そのうち95万件は既に廃止になっているとします。 このとき、 SELECT 売上トラン.* , 商品マスタ.商品名称 FROM 売上トラン INNER JOIN 商品マスタ ON 売上トラン.商品コード = 商品マスタ.商品名称 WHERE 商品マスタ.削除フラグ = '0' と書くのと、 SELECT 売上トラン.* , 商品マスタ.商品名称 FROM 売上トラン INNER JOIN (SELECT * FROM 商品マスタ WHERE 商品マスタ.削除フラグ = '0') 商品マスタ ON 売上トラン.商品コード = 商品マスタ.商品名称 と書くのだと、検索は下の方が速くなったりしますか? イメージですが、 上だと全件同士でくっつけた後で削るのに対して、 下だと削って5万件だけになったものをっつけていて、下の書き方の方が良いのかな? と思ったものの、どこかの本などでこういう書き方が良いと読んだわけではないので、 イメージであっているのか、それとも変わらないのか質問しました。 また、削除フラグのように1か0の2値しかとらない項目については、 INDEXを張る効果はあるでしょうか? ちなみにverで挙動が変わるかわかりませんが、環境はoracle11gを想定した場合となります。

  • Oracle
  • 回答数4
  • ありがとう数15

みんなの回答

  • entree
  • ベストアンサー率55% (405/735)
回答No.4

> 検索は下の方が速くなったりしますか? 統計情報が正しく取られているなら速くはならないでしょう(同じということ)。 売上トランの件数にもよりますが(※)、どちらも商品マスタを削除フラグ = '0' で絞ってから結合という実行計画になると思われます。 ただし、上の記述の方がシンプルなのでおすすめします。複雑な記述はオプティ マイザを惑わせたり、オラクルの不具合を引く確率を高めたりするので。 ※絞り込んだ後も商品マスタの件数が5万件と大きめなので、例え売上トラン.  商品コード列に索引があったとしても、ハッシュ結合が選択される可能性があ  ります。 > また、削除フラグのように1か0の2値しかとらない項目については、 > INDEXを張る効果はあるでしょうか? 例え2値しかなくても、1/20に絞り込まれるわけですから大いにあります。バイ ンド変数を使用していないならなおさらです。最近のオラクルは賢いのでテーブ ルのどの列が検索条件 (WHERE 句等) で使用されるかモニタリングし、検索に使 用される列だけヒストグラム統計を取ってくれるようになっていますが、自動的 に取ってくれない場合は手動で取る必要があります。

  • pringlez
  • ベストアンサー率36% (598/1630)
回答No.3

もしかしたら同じアクセスパスになるかもしれません。 しかしこの2つのSQLであればおそらくはあなたの想像通りに ・1つめだったら結合して、大きなテーブルを作ってから絞込み、 ・2つめだったら商品マスタを絞ってから結合 になると思います。 しかし確かなことは実行しなければ分かりません。例えば同じSQLでもレコード数によってもアクセスパスは変わります。また、同じSQL・同じレコード数でも、実行時間が長いときにはより最適な方法を探そうとしてアクセスパスが変わることもあります。導入当初と運用中にアクセスパスが変わるのはよく発生することなので、「導入したときはこうだったんだけど…」といわずに毎週もしくは毎月のようにチェックをしたほうがいいです。とにかく想像して終わりなのではなく、STATSPACKをとるなどして実際のアクセスパスを確認するようにしましょう。 というか普通に SELECT 売上トラン.* , 商品マスタ.商品名称 FROM 売上トラン INNER JOIN 商品マスタ ON 売上トラン.商品コード = 商品マスタ.商品名称 AND 商品マスタ.削除フラグ = '0' とすればいいのに、なぜ結合してから絞るの?と思ってしまいます。 >また、削除フラグのように1か0の2値しかとらない項目については、 >INDEXを張る効果はあるでしょうか? この検索の仕方でかつ、100万件のデータでかつ、取得するのが5万件なら確実に効果はあります。そして確実に先に絞り込むためにあなたの2つ目のSQLか、私の書いたSQLにしてみましょう。これこそ実測して確かめたほうがいいですよ。どのくらい効果があるのか理解できるでしょうから。 あと、お勧めでいうと、廃止したデータがそんなに多いのなら、廃止データは別テーブルに移動したほうがいいですよ。通常は有効な商品を使った検索が多いのでしょうから。そうすればインデックスを使うよりはるかに速く検索できます。で、廃止もふくめて検索する場合には2つのテーブルをUNIONするのはどうでしょう。

noname#212058
noname#212058
回答No.2

統計情報がきちんと取られているのなら、おそらくどちらも 変わらないと思います。 上のSQLの場合『全件同士でくっつけた後で削る』動きになる とは限りません。『くっつける』ほうが先か『削る』ほうが先 かは、ORACLE が自動的にどっちが効率的かを判断して決め ます。このケースでは 商品マスタ.削除フラグ = '0' の件数が 明らかに少ないので、おそらく『削る』ほうが先に動くかと 思います。 『ORACLE が自動的にどっちが効率的かを判断して決める』 機能を『オプティマイザ』といい、オプティマイザが決めた 処理順序を『実行計画』と言います。どちらもDBのパフォー マンスを語る場合には避けて通れません。 SQL の効率の良さは実行計画を比べると判ります。もし、 実際の ORACLE 上で問題の2つの SQL を実行できるのであ れば、以下のページを参考に実行計画を取得してみましょう。 http://d.hatena.ne.jp/replication/20130829/1377814308 Cost や Time の項目から効率を見ることができます。 # この機能を使えば、遅くて困っているSQLの原因を調べるこ # とも可能です。

  • bin-chan
  • ベストアンサー率33% (1403/4213)
回答No.1

やってみないと、ではあるがフラグ判定してJOINの方がよさそう。 > 削除フラグのように1か0の2値しかとらない項目については、 ビットマップインデックスでしょうね

関連するQ&A

  • SQLについて

    以下のSQLを実行すると。 SQL実行中に以下のエラーが発生しました。 エラーコード:907 [Oracle][ODBC][Ora]ORA-00907: 右カッコがありません。 というエラーが表示されます。 どこがおかしいでしょうか? SELECT Q1.Pコード, Q1.Qコード, T1.E名称 A名称, T2.E名称 B名称, T3.E名称 C名称, T4.E名称 D名称, FROM ( ( ( ( SELECT Pコード, Qコード, Aコード, Bコード, Cコード, Dコード, FROM 報告書 WHERE Pコード = '0001' AND Qコード = '0001' AND ) Q1 INNER JOIN Eマスタ T1 ON Q1.Aコード = T1.Eコード ) INNER JOIN Eマスタ T2 ON Q1.Bコード = T2.Eコード ) INNER JOIN Eマスタ T3 ON Q1.Cコード = T3.Eコード ) INNER JOIN Eマスタ T4 ON Q1.Dコード = T4.Eコード ORDER BY Pコード, Qコード;

  • SQLの書き方について

    下記のSQL文に科目マスタから科目名を取得する文を追加したいと考えてます。 色々と考えてみたのですが、私のスキルでは上手く行かなくて困っています。 どなたか教えて頂けないでしょう? 宜しくお願いします。 DB:アクセス97・アクセス2000 科目マスタ 科目CD  科目名 SELECT U.商品CD, 商品マスタ.商品名, U.[部署CD], 部署マスタ.部署名, U.SUM受払数 FROM 部署マスタ INNER JOIN ((SELECT 商品CD,受払年月日,部署CD,SUM(受払数) as SUM受払数 FROM 受払TBL WHERE 受払年月日 = '20110510' GROUP BY 商品CD,部署CD,受払年月日,受払数) AS U INNER JOIN 商品マスタ ON U.商品CD = 商品マスタ.商品CD) ON 部署マスタ.部署CD = U.部署CD ORDER BY U.商品CD, U.[部署CD], U.受払年月日, U.[SUM受払数] 科目名を取得する文を追加後のSQL文 SELECT U.商品CD, 商品マスタ.商品名, U.部署CD, 部署マスタ.部署名, U.科目CD, 科目マスタ.科目名, U.SUM受払数 FROM 部署マスタ INNER JOIN ((SELECT 商品CD,受払年月日,部署CD,科目CD,SUM(受払数) as SUM受払数 FROM 受払TBL WHERE 受払年月日 = '20110510' GROUP BY 商品CD,部署CD,受払年月日,科目CD,受払数 ) AS U INNER JOIN 商品マスタ ON U.商品CD = 商品マスタ.商品CD INNER JOIN 科目マスタ ON U.科目CD = 科目マスタ.科目CD ) ON 部署マスタ.部署CD = U.部署CD ORDER BY U.商品CD, U.部署CD, U.受払年月日, U.科目CD, U.SUM受払数 上記のSQLを実行するとエラーになります。 SQL実行中に以下のエラーが発生しました。 エラーコード:-3100 [Microsoft][ODBC Microsoft Access Driver] クエリ式 'U.商品CD = 商品マスタ.商品CD INNER JOIN 科目マスタ ON U.科目CD = 科目マスタ.科目CD' の 構文エラー : 演算子がありません。 SQLステータス:37000 宜しくお願いします。

  • SQL文を教えて下さい

    VB2008、SQL Server で開発をしています。 下記の条件でデータを取得したいのですが、SQL文がうまくできず、困っています。 おわかりの方、教えてください。 仕様:得意先マスタ(得意先M)の全件と、売上テーブル(売上T)を読みます。     売上テーブルの商品コードの商品名を商品マスタ(商品M)より取得します。     得意先マスタの全得意先を取得する必要があります。     すべての得意先の売上データが存在するわけではありません。 ACCESS上でクエリを作成し、SQLビューにすると、こうなります。 inptSyoCD:画面から入力した商品コード 1,まず、クエリ1: SELECT 売上T.伝票日付, 売上T.伝票番号, 売上T.得意先コード, 売上T.明細区分, 売上T.商品コード, 商品M.商品名称 FROM 売上T LEFT JOIN 商品M 売上T.商品コード = 商品M.商品名 WHERE 売上T.明細区分=1 AND 売上T.商品コード= inptSyoCD ; 2,次に、実際に処理するSQL文: SELECT 得意先M.得意先コード, 得意先M.得意先名称,       クエリ1.伝票日付, クエリ1.伝票番号, クエリ1.明細区分, クエリ1.商品コード, クエリ1.商品名  FROM 得意先M LEFT JOIN クエリ1 ON 得意先M.得意先コード = クエリ1.得意先コード ORDER BY 得意先M.得意先コード,売上T.伝票日付,売上T.商品コード; この2つをひとつのSQL文にする方法がわかりません。 よろしくお願いいたします。

  • SQLのエラーについて

    SQLの初心者です。 アクセス2000で下記のSQLを実行するとエラーになります。 SQLの書き方に問題が有るのでしょうか? どなたか教えて頂けたら幸いです。 宜しくお願いします。 エラーの内容 SQL実行中に以下のエラーが発生しました。 エラーコード:-3100 [Microsoft][ODBC Microsoft Access Driver] クエリ式 'U.商品CD=商品マスタ.商品CD INNER JOIN 部署マスタ ON U.部署CD=部署マスタ.部署CD' の 構文エラー : 演算子がありません。 SQLステータス:37000 SQLの内容 SELECT U.商品CD,商品マスタ.商品名,U.受払年月日,U.部署CD,部署マスタ.部署名, U.SUM受払数 AS 受払数 FROM [SELECT 商品CD,受払年月日,部署CD,SUM(受払数) as SUM受払数 FROM 受払TBL WHERE 受払年月日 = 20110513 GROUP BY 商品CD,部署CD,受払年月日,受払数] AS U INNER JOIN 商品マスタ ON U.商品CD=商品マスタ.商品CD INNER JOIN 部署マスタ ON U.部署CD=部署マスタ.部署CD ORDER BY 商品CD,部署CD,受払年月日,受払数

  • ACCESS SQL 括弧について

    AS 売上の合計をAS 07売上の合計に変えたところ かっこの使い方が正しくないと言われました。 ASの名前を変えただけなのですが、何が問題なのでしょうか? SELECT IIf([07売上の合計]=[売上],"●","×") AS 比較 FROM [SELECT ■T_M店マスタ.企業コード, ■T_M店マスタ.データレベル, Sum(■売上三期.[07年_売上]) AS 07売上の合計 FROM ■T_M店マスタ INNER JOIN ■売上三期 ON ■T_M店マスタ.店コード = ■売上三期.店コード GROUP BY ■T_M店マスタ.企業コード, ■T_M店マスタ.データレベル HAVING (((■T_M店マスタ.データレベル)="10"))]. AS 店 INNER JOIN [SELECT [●T_K調査データ(売上)企業レベル(単独店込み)].企業コード, [●T_K調査データ(売上)企業レベル(単独店込み)].売上, Format(DateAdd("m",-6,CDate("H" & Left([決算期],2) & "年" & Right([決算期],2) & "月")),"yyyy" & "年") AS 式1 FROM [●T_K調査データ(売上)企業レベル(単独店込み)] WHERE (((Format(DateAdd("m",-6,CDate("H" & Left([決算期],2) & "年" & Right([決算期],2) & "月")),"yyyy" & "年"))="2007年"))]. AS 企業 ON 店.企業コード = 企業.企業コード WHERE (((IIf([07売上の合計]=[売上],"●","×"))="×"));

  • sqlについて

    下に書いたsqlのコードの内容(どういう処理でどういう結果になるのか)が知りたいです。 どなたかわかる方教えてください。 select b.ym, b.no,     isnull(e.sumcnt,0)as val, null as bunsi, null as bunbo from (select distinct ym,no from Table_A)b inner join (select ym from Table_B where cd=1)d on b.ym=d.ym left outer join (select b1.ym,b1.no,sum(c1.cnt)as sumcnt from Table_A b1 inner join (select ym from Table_B where cd=1)d1 on b1.ym=d1.ym inner join Table_C c1 on b1.ym=c1.ym group by b1.ym,b1no)e on b.ym=e.ym and b.no=e.no

  • inner joinでサブクエリ

    SQLについてお教え頂けませんでしょうか? 在庫テーブル ・ID ・数量 データ 001,1 001,3 002,3 002,2 002,4 003,2 商品テーブル ・ID データ 001 002 003 004 やりたいこと: 在庫テーブルには重複しているIDがあります。 商品テーブルには重複しているIDはありません。 在庫テーブルの重複を削除したIDと商品テーブルのIDをinner joinで結びたいと思います。 ・select distinct ID FROM 在庫テーブル ・select ID FROM 商品テーブル この2つのjoin方法がわかりません。 結果として、 001 002 003 を取得したいいです。宜しくお願いします。 ちなみに select ID from 商品テーブル inner join 在庫テーブル 商品テーブル.ID = exists(select distinct ID from 在庫テーブル) というコードを書きましたが、動きませんでした・・・抽出データが0件でした・・・

  • SQL文のエラーについて

    下記のSQL文な実行するとエラーになってしまいます。 数時間考えましたが、上手く行きません。 どなたか教えて頂けないでしょう? 宜しくお願いします。 DB:アクセス97 アクセス2000 SQL実行中に以下のエラーが発生しました。 エラーコード:-3010 [Microsoft][ODBC Microsoft Access Driver] パラメータが少なすぎます。1 を指定してください。 SQLステータス:07001 SELECT mid(U.受払年月日,1,6), U.部門CD, 部門マスタ.部門名, U.商品CD, 商品マスタ.商品名, U.科目CD, 科目マスタ.科目名, U.SUM受払数 FROM (部門マスタ INNER JOIN ((SELECT mid(受払年月日,1,6),部門CD,商品CD,科目CD,SUM(受払数) as SUM受払数 FROM 受払TBL WHERE 受払年月日 BETWEEN '201101' and '201105' GROUP BY mid(受払年月日,1,6),部門CD,商品CD,科目CD) AS U INNER JOIN 商品マスタ ON U.商品CD = 商品マスタ.商品CD) ON 部門マスタ.部門CD = U.部門CD ) INNER JOIN 科目マスタ ON U.科目CD = 科目マスタ.科目CD ORDER BY U.受払年月日, U.部門CD, U.商品CD, U.科目CD

  • このSQLのおかしい所は?

    DB2環境です。 SQLを組んでみたのですが、どこかおかしいようでうまく値が とれません。 どこが問題になっているか教えていただけませんか? SELECT * FROM TR0410 r410 INNER JOIN TR0400 r400 ON r410.BILLMNGNO=r400.BILLMNGNO AND r400.DELETEFLG=0 INNER JOIN MR0010 mr10 ON (SELECT r10.BUILDMNGNO FROM TR0010 r10 INNER JOIN TR0410 r410 ON r10.ONKEINO=r410.ONKEINO)=mr10.BUILDMNGNO AND mr10.DELETEFLG=0 INNER JOIN MB0010 mb10 ON (SELECT r10.BUILDMNGNO FROM TR0010 r10 INNER JOIN TR0410 r410 ON r10.ONKEINO=r410.ONKEINO)=mb10.BUILDMNGNO AND mb10.DELETEFLG=0 AND mb10.BUILDTNO=(SELECT MIN(BUILDTNO) FROM MB0010 b10EX WHERE b10EX.BUILDMNGNO=mb10.BUILDMNGNO) INNER JOIN TR0010 r10 ON r410.ONKEINO=r10.ONKEINO AND r410.ONKEISUB=r10.ONKEISUB AND r10.DELETEFLG=0 INNER JOIN TR0100 r100 ON r410.TNKEINO=r100.TNKEINO AND r410.TNKEISUB=r100.TNKEISUB AND r100.DELETEFLG=0 INNER JOIN TR0050 r50 ON r410.ONKEINO=r50.ONKEINO AND r410.ROOMCD=r50.ROOMCD AND r50.DELETEFLG=0 INNER JOIN MR0030 mr30a ON r10.ONCD=mr30a.RESTORINO AND mr30a.DELETEFLG=0 INNER JOIN MR0030 mr30b ON r100.TENANTCD=mr30b.RESTORINO AND mr30b.DELETEFLG=0 WHERE r410.DELETEFLG=0 AND r410.SKYOTKBN=2 AND mr10.TORITENPO=1

  • テーブルの結合の仕方 MSAccess97→MSSQLServer2000Dev

    初心者なので初歩的な質問かもしれませんがどうぞよろしくお願いします。 現在MSAccess97(Win2K)のDBをVB6sp4(Win2K)で操作しておりますが、 MSAccess97のDBをMSSQLServer2000に移行しようと考えておりましてクエリー(VBで作成したクライアント内のSQL文)での記述のしかたについて質問したいのですが、下記のように○売上明細テーブルと○商品マスタが存在していて いままで(Access)は SELECT 売上明細.*,商品マスタ.* FROM 売上明細 LEFT JOIN 商品マスタ ON 売上明細.商品コード = 商品マスタ.商品コード; で結合して追加・削除・更新などしておりました。 商品マスタの内容は変更・削除しないで売上明細のほうは削除できました。 移行(MSSQLServer)しようとSQL文を書き直し SELECT 売上明細.*,商品マスタ.* FROM 売上明細 LEFT OUTER JOIN 商品マスタ ON 売上明細.商品コード = 商品マスタ.商品コード; として(SQLServerのDBを)削除すると商品マスタのほうまで削除されてしまいます。SQLServerのViewで直接削除してみても同じでした。 +-----+-------+--+----+-------+ |商品コード| 商品名   |単価| 数量 |  金 額  | +-----+-------+--+----+-------+ |00001 |        |50 |  20 |  1,000 |          ↑                              ここに設定する項目が売上明細にないので         商品マスタから参照したい(参照のみで更新・削除はしない)   SQLServerで商品マスタを変更・削除せずに商品明細のレコードを削除できる結合方法はないでしょうか?どなたかよろしくお願いいたします。