本当にあった怖い話しDB 編
プログラミング生放送勉強会 第 18 回 @ 大阪2012/11/03 お だ
自己紹介
織田 信亮 ( おだ しんすけ )大阪で開発者していますSQLWorld の代表です
http://d.hatena.ne.jp/odashinsuke/Twitter:@shinsukeoda
SQLWorld とは
http://sqlworld.org/Twitter:@SQLWorld_JP次のような情報を発信しているコミュニティです
MS の RDBMS である「 SQL Server 」もちろん他の DB の話しも!正規化 / モデリングSQL/NoSQL
注意書き
特定の製品を挙げているように見えますが、最近よく使ってるからだけで他意はありません!体験談で公式資料は見つけれてません!
本当にあった怖い話し _DB 編
その1:システム要件を満たしているのに動かない!その2:バインド変数が動かない!
ODP.NET 4 がシステム要件を満たしているのに動かない
http://docs.oracle.com/cd/E16338_01/win.112/b66456/InstallSystemRequirements.htm#i1006191
ODP.NET 4 がシステム要件を満たしているのに動かない
実行環境Windows XP SP3.NET Framework 4 Client Profile.NET 2 系は未インストール
ODP.NET 4標準の Widows Update は適用済み.NET 3.5 SP1 は除く
例外発生!!
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(); }}
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(); }}
例外発生!--------------------------------------------------------------------------------mscorelib, Version=4.0.0.0, ...Oracle.DataAccess, Version=4.112.3.0, ...'Oracle.DataAccess.Client.OracleConnection' type iniitalize error ....--------------------------------------------------------------------------------
ODP.NET 4 がシステム要件を満たしているのに動かない
回避策 ( どれか一つで OK)Windows Update から .NET 3.5 SP1 をインストールC++ の再頒布可能パッケージ をインストール
http://www.microsoft.com/ja-jp/download/details.aspx?id=5638
OTN Discussion ForumsODP.NET4 required .NET2.0?
https://forums.oracle.com/forums/thread.jspa?threadID=2423728&stqc=true
バインド変数に長い文字列を指定すると動かない
某 9i で発生!10g, 11g では発生せず
バインド変数の値が 2000 文字 (ASCII) 以上の物が複数存在するとエラーが発生
ORA-01461 :LONG 値は LONG 列にのみバインドできます。
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 文字
バインド変数に長い文字列を指定すると動かない
回避策9i を使わないクエリ内で文字列結合を行い、 1 バインド変数の文字数が大きくならないようにする
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/
まとめ
変な書き方してるクエリを見つけても、バカにしない!意味の分からない事象にぶち当たっても泣かない!
ご清聴ありがとうございました
本当にあった怖い話し _DB 編
おまけ:ストアド × ファンクションで…
本当にあった怖い話し _DB 編
おまけ:ストアド × ファンクションで…
┌(┌^o^)┐ ホモォ ...
本当にあった怖い話し _DB 編
おまけ:ストアド × ファンクションで…
┌(┌^o^)┐ ホモォ ...
ストアド内で複数回呼び出しているファンクションのトランザクションが異なる
11g で発生非常に複雑なストアド内で同じファンクションを何回も参照している時に発生
cursor共通テーブル式with cte as (select ~)
window 関数 sum() over (partition by ~ )
union all
サンプルクエリの説明
FOO テーブルマスタテーブル
BAR_FUNCFOO.HOGE_KBN が ‘ 1’ はエラー発生FOO.HOGE_KBN が ‘ 2’ はエラーなし
ZOO_PROCEDUREFOO 、 BAR_FUNC を参照トランザクションテーブルを更新FOO テーブルは更新しない
FOO テーブルのデータ BAR_FUNC との関係HOGE_KBN‘1’ エラー‘2’ エラーなし
BAR_FUNC では検証用に RAISE_APPLICATION_ERROR を使ってエラーを発生させている
-- 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’ なのにエラー発生!! /
ストアド内で複数回呼び出しているファンクションのトランザクションが異なる
BAR_FUNC 内で、 FOO テーブルのデータを確認してみると…
エラーが起きる時は、何故か更新前のデータを参照している
同一トランザクション内で更新したはずのデータが見れてない!
ストアド内で複数回呼び出しているファンクションのトランザクションが異なる
cursor と 共通テーブル式を辞めても発生window 関数か union all を辞めると発生しなかったw indow 関数と union all を使ったシンプルなストアドだと発生しなかった再現するミニマムクエリを発見出来ず…
ストアド内で複数回呼び出しているファンクションのトランザクションが異なる
回避策window 関数は削れなかったので、 union all を諦めて、 2 つのクエリに分けた。本当に回避出来てるのか不明。原因を探れていないので、本当に発生しないのかは不明。テストでは再現しなかった。
まとめ
変な書き方してるクエリを見つけても、バカにしない!テストは大事!意味の分からない事象にぶち当たっても泣かない!
ご清聴ありがとうございました