@IT会議室は、ITエンジニアに特化した質問・回答コミュニティ「QA@IT」に生まれ変わりました。ぜひご利用ください。
- PR -

SQLServer2005へのInsertでエラーにならないのにInsertされないことがある

1
投稿者投稿内容
hana@kaori
会議室デビュー日: 2008/04/11
投稿数: 2
投稿日時: 2008-04-11 19:22
こちらでよいのかどうか分からなかったので、間違っていたらご指摘ください。

【開発環境】
WindowsXP SP2
VB6.0
ADO 2.8

【Serever】
WindowsServer2003 SP1
SQLServer2005 SP2


TableX
--------------------
ID int
DT datetime
TYP int
TM int
--------------------
主キーはありません。(客先都合により)

TableXに対して、ほぼ同時に同じDTのInsert文を発行したとき、先勝ちになってしまいます。
何故そのようになるのか、ご存知の方がおられましたら教えてください。


挙動
--------------------------------------
1.A、B、C、Dの4つのプロセスがあります。
2.4つのプロセスはパラで実行し、稀に2つ以上のプロセスがほぼ同時(1秒以内)に実行することもあります。
3.1秒以内に同時に実行した場合、DT列に全く同じ日時(YYYY/MM/DD HH24:MI:SS)でInsert文を発行します。 ←この時、Insertエラーが起こらず、コミット出来るのにデータが存在しません。(IDでSelectしても見つかりません。)
ミリ秒に違う値が入るようにすると、正常にInsertされました。
---------------------------------------

具体例)プロセスAとプロセスBがほぼ同時に実行した場合

1.プロセスA:Insert Into TableX (ID,DT,TYP,TM) Valuse(1,Convert(datetime,"2008/04/11 16:15:10",1,161510)

2.プロセスB:Insert Into TableX (ID,DT,TYP,TM) Valuse(2,Convert(datetime,"2008/04/11 16:15:10",2,161510)

3.Select count(*) From TableX Where ID = 2
 count(*) = 0  ← 本来なら1になるはず!!!

 
成功例)プロセスAとプロセスBがほぼ同時に実行した場合

1.プロセスA:Insert Into TableX (ID,DT,TYP,TM) Valuse(1,Convert(datetime,"2008/04/11 16:15:10.000",1,161510)

2.プロセスB:Insert Into TableX (ID,DT,TYP,TM) Valuse(2,Convert(datetime,"2008/04/11 16:15:10.100",2,161510)

3.Select count(*) From TableX Where ID = 2
 count(*) = 1  ← 1になる


私の認識では、データベースではこんなことありえないと思うのですが、こういうものなのでしょうか?

アプリケーション側のエラートラップは、On Error でトラップしています。
また、オートコミットモードでも、明示的にトランザクション処理をした場合もダメでした。
SQLServerのトレースでは、SQLはコンプリートし、コミットも実行されていて、ロールバックは起きていません。


SPなしのSQLServer2005で実行したところ、イベントビューアに下記ログが出力されていました。
▼SQL Server 2005 でトランザクションをロールバックした後、エラー メッセージ:"エラー: 3315
http://support.microsoft.com/kb/917886/ja#appliesto


このことから、勝手にロールバックしているようなのですが、オートコミットモードでも起きていて、SQLトレースにも出てきません。

一体、何が起こっているのでしょうか?
masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2008-04-11 21:30
主キーのないテーブルに同時に更新を行うと、この現象が起こる可能性があるようです。
おそらくSQLServer内部でエラーが起こり、トランザクションはロールバックされています。
問題なのが、そのエラーがADO側に渡されないことです。

そのため、コミットまたはロールバックを行うと、
既にトランザクションは終了しているという内容のエラーが発生します。

ADO.NETで同じような現象にあったことがあります。


オートナンバーのような列を主キーとして追加することはできませんか?

Accessでも同様ですが、
主キーがないテーブルでは全ての列の値が等しいかどうかで排他に関する何らかの制御が行われているのではないかと思います。
ですので、時刻の値を変えた場合には衝突が起こらないのでしょう。


[ メッセージ編集済み 編集者: masa 編集日時 2008-04-11 21:33 ]

[ メッセージ編集済み 編集者: masa 編集日時 2008-04-11 21:34 ]
hana@kaori
会議室デビュー日: 2008/04/11
投稿数: 2
投稿日時: 2008-04-15 10:46
masaさん

回答ありがとうございます。

テーブルは客先範疇のため、
 datetime型のカラムにミリ秒で区別を付けるか
 主キーを追加して貰うか
の提案をしたいと思います。

masa
大ベテラン
会議室デビュー日: 2004/10/28
投稿数: 161
投稿日時: 2008-04-15 13:35
同時接続数やアプリケーションの内容にもよりますが、
ミリ秒であっても以外と衝突するものです。1000分の1になるだけですから。

経験的には何れかの列の値が異なっていればこの現象はでないようですので、
連番のような値を格納する列を追加しておけば、それが主キーかどうかは問われないと思います。

ですが、全ての列の値が一致しているかどうかで判定するというのは
パフォーマンス面であまりよいことではないと思いますので、
できれば主キーとしたほうがよいと思います。


_________________
............................................................................................
masa          blog 始めてみました。
[ track4 labo. ]
http://maasa.cside.com/blog/track4labo/
1

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