本当にあった怖い話し Db編

2,233 views

Published on

プログラミング生放送勉強会 第18回@大阪

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,233
On SlideShare
0
From Embeds
0
Number of Embeds
161
Actions
Shares
0
Downloads
5
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

本当にあった怖い話し Db編

  1. 1. 本当にあった怖い話しDB 編 プログラミング生放送勉強会 第18回@大阪 2012/11/03 お だ
  2. 2. 自己紹介織田 信亮(おだ しんすけ)大阪で開発者していますSQLWorld の代表ですhttp://d.hatena.ne.jp/odashinsuke/Twitter:@shinsukeoda
  3. 3. SQLWorld とはhttp://sqlworld.org/Twitter:@SQLWorld_JP次のような情報を発信しているコミュニティです MS の RDBMS である「SQL Server」 もちろん他の DB の話しも! 正規化/モデリング SQL/NoSQL
  4. 4. 注意書き特定の製品を挙げているように見えますが、最近よく使ってるからだけで他意はありません!体験談で公式資料は見つけれてません!
  5. 5. 本当にあった怖い話し_DB 編その1:システム要件を満たしているのに動かない!その2:バインド変数が動かない!
  6. 6. ODP.NET 4 がシステム要件を満たしているのに動かないhttp://docs.oracle.com/cd/E16338_01/win.112/b66456/InstallSystemRequirements.htm#i1006191
  7. 7. ODP.NET 4 がシステム要件を満たしているのに動かない 実行環境 Windows XP SP3 .NET Framework 4 Client Profile .NET 2系は未インストール ODP.NET 4 標準の Widows Update は適用済み .NET 3.5 SP1 は除く 例外発生!!
  8. 8. using System;using Oracle.DataAccess.Client;class Program { static void Main(string[] args) { try { Console.WriteLine(typeof(string).Assembly.FullName); Console.WriteLine(typeof(OracleConnection).Assembly.FullName); var connStr = “~"; using (var conn = new OracleConnection(connStr)) using (var cmd = new OracleCommand(@"select SYSDATE from dual", conn)) { conn.Open(); Console.WriteLine(cmd.ExecuteScalar()); } } catch (Exception e) { Console.WriteLine(e.Message); Console.WriteLine(e.StackTrace); } Console.ReadKey(); }}
  9. 9. using System;using Oracle.DataAccess.Client;class Program { static void Main(string[] args) { try { Console.WriteLine(typeof(string).Assembly.FullName); 例外発生! Console.WriteLine(typeof(OracleConnection).Assembly.FullName); var connStr = “~"; using (var conn = new OracleConnection(connStr)) using (var cmd = new OracleCommand(@"select SYSDATE from dual", conn)) { -------------------------------------------------------------------------------- conn.Open(); mscorelib, Version=4.0.0.0, ... Console.WriteLine(cmd.ExecuteScalar()); Oracle.DataAccess, Version=4.112.3.0, ... } Oracle.DataAccess.Client.OracleConnection type iniitalize } catch (Exception e) { Console.WriteLine(e.Message); error .... Console.WriteLine(e.StackTrace); -------------------------------------------------------------------------------- } Console.ReadKey(); }}
  10. 10. ODP.NET 4 がシステム要件を満たしているのに動かない 回避策 (どれか一つでOK) Windows Update から .NET 3.5 SP1 をイン ストール C++ の再頒布可能パッケージ をインストー ル http://www.microsoft.com/ja-jp/download/details.aspx?id=5638 OTN Discussion Forums ODP.NET4 required .NET2.0? https://forums.oracle.com/forums/thread.jspa?thr eadID=2423728&stqc=true
  11. 11. バインド変数に長い文字列を指定すると動かない 某9i で発生! 10g, 11g では発生せずバインド変数の値が 2000文字(ASCII) 以上の物が複数存在するとエラーが発生ORA-01461:LONG値はLONG列にのみバインドできます。
  12. 12. create table TEST ( PK number(3,0) not null primary key, CONTENT1 varchar2(4000), CONTENT2 varchar2(4000), CONTENT3 varchar2(4000))/insert into TEST values (:PK, :CONTENT1, :CONTENT2, :CONTENT3)/drop table TEST/ 結果 CONTENT1 CONTENT2 CONTENT3 NG 4000文字 4000文字 4000文字 NG 2000文字 2000文字 0文字 OK 1999文字 2000文字 1999文字 OK 1999文字 4000文字 1999文字
  13. 13. バインド変数に長い文字列を指定すると動かない 回避策 9i を使わない クエリ内で文字列結合を行い、1バインド変 数の文字数が大きくならないようにする
  14. 14. create table TEST ( PK number(3,0) not null primary key, CONTENT1 varchar2(4000), CONTENT2 varchar2(4000), CONTENT3 varchar2(4000))/insert into TEST values ( :PK, :CONTENT1_1 || :CONTENT1_2 || :CONTENT1_3 || :CONTENT1_4, :CONTENT2_1 || :CONTENT2_2 || :CONTENT2_3 || :CONTENT2_4, :CONTENT3_1 || :CONTENT3_2 || :CONTENT3_3 || :CONTENT3_4)/drop table TEST/
  15. 15. まとめ変な書き方してるクエリを見つけても、バカにしない!意味の分からない事象にぶち当たっても泣かない!
  16. 16. ご清聴ありがとうございました
  17. 17. 本当にあった怖い話し_DB 編おまけ:ストアド × ファンクションで…
  18. 18. 本当にあった怖い話し_DB 編おまけ:ストアド × ファンクションで… ┌(┌^o^)┐ホモォ...
  19. 19. 本当にあった怖い話し_DB 編おまけ:ストアド × ファンクションで… ┌(┌^o^)┐ホモォ...
  20. 20. ストアド内で複数回呼び出しているファンクションのトランザクションが異なる 11g で発生 非常に複雑なストアド内で同じファンク ションを何回も参照している時に発生 cursor 共通テーブル式 with cte as (select ~) window 関数 sum() over (partition by ~) union all
  21. 21. サンプルクエリの説明FOO テーブル マスタテーブルBAR_FUNC FOO.HOGE_KBN が ‘1’ はエラー発生 FOO.HOGE_KBN が ‘2’ はエラーなしZOO_PROCEDURE FOO、BAR_FUNC を参照 トランザクションテーブルを更新 FOO テーブルは更新しない
  22. 22. FOO テーブルのデータ BAR_FUNC との関係HOGE_KBN‘1’ エラー‘2’ エラーなしBAR_FUNC では検証用にRAISE_APPLICATION_ERRORを使ってエラーを発生させている
  23. 23. -- FOO.HOGE_KBN = ‘1’ はエラー発生、’2’ はエラー発生せずupdate FOO set HOGE_KBN = 1/commit/select BAR_FUNC(~) from dual -- FOO.HOGE_KBN = ‘1’ なのでエラー発生/update FOO set HOGE_KBN = 2/select BAR_FUNC(~) from dual -- FOO.HOGE_KBN = ‘2’ なのでエラー発生せず/rollback/call ZOO_PROCEDURE (~) -- FOO.HOGE_KBN = ‘1’ なのでエラー発生/update FOO set HOGE_KBN = 2/call ZOO_PROCEDURE (~) -- FOO.HOGE_KBN = ‘2’ なのにエラー発生!!/
  24. 24. ストアド内で複数回呼び出しているファンクションのトランザクションが異なる BAR_FUNC 内で、FOO テーブルのデータを 確認してみると… エラーが起きる時は、何故か更新前のデー タを参照している 同一トランザクション内で更新したはず の データが見れてない!
  25. 25. ストアド内で複数回呼び出しているファンクションのトランザクションが異なる cursor と 共通テーブル式を辞めても発 生 window 関数か union all を辞めると発 生しなかった window 関数と union all を使ったシン プルなストアドだと発生しなかった 再現するミニマムクエリを発見出来ず…
  26. 26. ストアド内で複数回呼び出しているファンクションのトランザクションが異なる 回避策 window 関数は削れなかったので、union all を諦めて、2つのクエリに分けた。 本当に回避出来てるのか不明。 原因を探れていないので、本当に発生しないのか は不明。 テストでは再現しなかった。
  27. 27. まとめ変な書き方してるクエリを見つけても、バカにしない!テストは大事!意味の分からない事象にぶち当たっても泣かない!
  28. 28. ご清聴ありがとうございました

×