- - PR -
【バグ】リンクサーバーから嘘の結果が返ってくる【SQL SERVER 2005】
1|2|3|4|5
次のページへ»
投稿者 | 投稿内容 | ||||
---|---|---|---|---|---|
|
投稿日時: 2008-02-26 00:41
いつもお世話になっております。
2台のSQL SERVER 2005(SP2)でリンクサーバーを使っているのですが、 リンクサーバー越しに複数のテーブルを結合するクエリ(select文) を流したところ、明らかに誤った結果が返ってきました。 具体的には抽出条件により、同一のレコードの内容が変化するというものです。 結合結果を全件出力すると 列1,列2 A, 1 B, 2 B, 3 C, 5 となるのに、列1=B の条件を追加すると B, 2 B, 5 というようにありえない結果が返されてきます。 現象の再現性はあるものの、問題が発生するレコードは抽出条件によって変化します。 また、リンクサーバー側で直接同じクエリを流すと正しい結果が得られます。 これはSQL SERVER のバグでしょうか? リンクサーバーのテーブルを結合すると正しい結果は得られないものなのでしょうか? ご存知の方おられましたらよろしくお願いいたします。 [ メッセージ編集済み 編集者: ハニワ祭り 編集日時 2008-05-05 00:53 ] | ||||
|
投稿日時: 2008-02-26 15:06
SQLが提示されてないので憶測になりますが、スレ主さんがおっしゃる処の全件出力時 のSQLすら正しくないのではないかと・・・。 まあ、「バグですか」と問うなら、最低でもSQL位は提示して下さい。 | ||||
|
投稿日時: 2008-02-27 01:11
上総さんのおっしゃるとおり、
確実に問題が発生するSQLを提示したいのですが、 実際には数万件のデータより数100件を抽出した際に問題が発生したため、 現象が発生する最小限の環境 (必要なデータ量、テーブル構成、インデックスの張り方、プロセッサ数など) を特定できておりません。 公開可能な範囲で再現性のあるクエリ及びデータを特定出来た際に 再度報告させていただきます。 いちおうクエリの概要ですが、 簡単に書くと以下のような感じになりますが、 数件程度のデータで試しても恐らく現象は再現しません… SELECT * FROM ( SELECT WK1.項目1 AS 列1 CASE WHEN 条件 THEN (SELECT 〜) ←項目1をキーに相関副問い合わせでテーブル「TA」より名称取得 ELSE '' END AS 列2 , CASE WHEN 条件 THEN SUBSTRING(WK1.項目1,5,4) ←項目1より文字の一部分を切り出す ELSE WK1.項目2 END AS 列3 , WK1.項目3 AS 列4 FROM ( SELECT 〜 FROM T1, T2 ←キーで結合 UNION ALL SELECT 〜 FROM T1, T2 ←キーで結合 UNION ALL SELECT 〜 FROM T3 ) AS WK1 ) AS WK2 WHERE WK2.列3 = 'XXXX' ←ケース文の条件に当てはまった場合に切り出した文字で抽出 ※T1,T2,T3,TAは全てリンクサーバー側のテーブルを指定してあるものと 思ってください。 最終行のWHERE句を指定した場合のみ結果がおかしく 列1と列2が絶対にありえない(集合理論を無視した)組み合わせでデータが 出力されることがあります。 [ メッセージ編集済み 編集者: ハニワ祭り 編集日時 2008-02-27 01:24 ] | ||||
|
投稿日時: 2008-02-27 12:15
SQLを拝見しましたが、確かに問題が発生する可能性は低そうです。
(列に副問い合わせを指定している箇所がなんとはなしに危なそうですが) 相関副問い合わせを使用せずに、『LEFT JOIN』を使用してみたらどうでしょうか? 取りあえず列2を取り出す箇所のみを修正しています。
| ||||
|
投稿日時: 2008-02-27 19:06
現象の再現方法がわかりました。
手順と結果は以下のようになります。 -------------------------------------------------------- -- @準備処理(データベース「AAA」に対してテーブル作成) -------------------------------------------------------- CREATE TABLE [dbo].[T2]( [ID] [char](3) NOT NULL, [CODE] [char](2) NOT NULL CONSTRAINT [PK_T1_1] PRIMARY KEY CLUSTERED ([ID] ASC) ) GO CREATE TABLE [dbo].[M2]( [CODE] [char](2) NOT NULL, [NAME] [varchar](20) NOT NULL, CONSTRAINT [PK_M2_1] PRIMARY KEY CLUSTERED ([CODE] ASC) ) GO INSERT INTO [dbo].[T2] VALUES ( '001', '66') INSERT INTO [dbo].[T2] VALUES ( '002', '66') INSERT INTO [dbo].[T2] VALUES ( '003', '66') INSERT INTO [dbo].[T2] VALUES ( '004', '66') INSERT INTO [dbo].[T2] VALUES ( '005', '77') INSERT INTO [dbo].[T2] VALUES ( '006', '55') INSERT INTO [dbo].[T2] VALUES ( '007', '88') INSERT INTO [dbo].[T2] VALUES ( '008', '88') INSERT INTO [dbo].[T2] VALUES ( '009', '77') INSERT INTO [dbo].[T2] VALUES ( '010', '66') INSERT INTO [dbo].[T2] VALUES ( '011', '77') INSERT INTO [dbo].[T2] VALUES ( '012', '66') INSERT INTO [dbo].[T2] VALUES ( '013', '66') INSERT INTO [dbo].[T2] VALUES ( '014', '88') INSERT INTO [dbo].[T2] VALUES ( '015', '88') INSERT INTO [dbo].[T2] VALUES ( '016', '88') INSERT INTO [dbo].[T2] VALUES ( '017', '22') INSERT INTO [dbo].[T2] VALUES ( '018', '88') INSERT INTO [dbo].[T2] VALUES ( '019', '88') INSERT INTO [dbo].[T2] VALUES ( '020', '88') INSERT INTO [dbo].[T2] VALUES ( '021', '44') INSERT INTO [dbo].[T2] VALUES ( '022', '88') INSERT INTO [dbo].[T2] VALUES ( '023', '66') INSERT INTO [dbo].[T2] VALUES ( '024', '66') INSERT INTO [dbo].[T2] VALUES ( '025', '77') INSERT INTO [dbo].[T2] VALUES ( '026', '77') INSERT INTO [dbo].[T2] VALUES ( '027', '77') INSERT INTO [dbo].[T2] VALUES ( '028', '66') INSERT INTO [dbo].[T2] VALUES ( '029', '66') INSERT INTO [dbo].[T2] VALUES ( '030', '66') INSERT INTO [dbo].[T2] VALUES ( '031', '44') INSERT INTO [dbo].[T2] VALUES ( '032', '77') INSERT INTO [dbo].[T2] VALUES ( '033', '44') INSERT INTO [dbo].[T2] VALUES ( '034', '66') INSERT INTO [dbo].[T2] VALUES ( '035', '88') INSERT INTO [dbo].[T2] VALUES ( '036', '88') INSERT INTO [dbo].[T2] VALUES ( '037', '66') INSERT INTO [dbo].[T2] VALUES ( '038', '66') INSERT INTO [dbo].[T2] VALUES ( '039', '77') INSERT INTO [dbo].[T2] VALUES ( '040', '77') INSERT INTO [dbo].[T2] VALUES ( '041', '77') INSERT INTO [dbo].[T2] VALUES ( '042', '44') INSERT INTO [dbo].[T2] VALUES ( '043', '77') INSERT INTO [dbo].[T2] VALUES ( '044', '77') INSERT INTO [dbo].[T2] VALUES ( '045', '66') INSERT INTO [dbo].[T2] VALUES ( '046', '66') INSERT INTO [dbo].[T2] VALUES ( '047', '77') INSERT INTO [dbo].[T2] VALUES ( '048', '44') INSERT INTO [dbo].[T2] VALUES ( '049', '66') INSERT INTO [dbo].[T2] VALUES ( '050', '66') INSERT INTO [dbo].[T2] VALUES ( '051', '66') INSERT INTO [dbo].[T2] VALUES ( '052', '88') INSERT INTO [dbo].[T2] VALUES ( '053', '66') INSERT INTO [dbo].[T2] VALUES ( '054', '44') INSERT INTO [dbo].[T2] VALUES ( '055', '88') INSERT INTO [dbo].[T2] VALUES ( '056', '88') INSERT INTO [dbo].[T2] VALUES ( '057', '88') INSERT INTO [dbo].[T2] VALUES ( '058', '88') INSERT INTO [dbo].[T2] VALUES ( '059', '22') INSERT INTO [dbo].[T2] VALUES ( '060', '88') INSERT INTO [dbo].[T2] VALUES ( '061', '11') INSERT INTO [dbo].[T2] VALUES ( '062', '11') INSERT INTO [dbo].[T2] VALUES ( '063', '11') INSERT INTO [dbo].[T2] VALUES ( '064', '88') INSERT INTO [dbo].[T2] VALUES ( '065', '77') INSERT INTO [dbo].[T2] VALUES ( '066', '77') INSERT INTO [dbo].[T2] VALUES ( '067', '66') INSERT INTO [dbo].[T2] VALUES ( '068', '77') INSERT INTO [dbo].[T2] VALUES ( '069', '77') INSERT INTO [dbo].[T2] VALUES ( '070', '77') INSERT INTO [dbo].[T2] VALUES ( '071', '33') INSERT INTO [dbo].[T2] VALUES ( '072', '33') INSERT INTO [dbo].[T2] VALUES ( '073', '66') INSERT INTO [dbo].[T2] VALUES ( '074', '66') INSERT INTO [dbo].[T2] VALUES ( '075', '66') INSERT INTO [dbo].[T2] VALUES ( '076', '11') INSERT INTO [dbo].[T2] VALUES ( '077', '77') INSERT INTO [dbo].[T2] VALUES ( '078', '11') INSERT INTO [dbo].[T2] VALUES ( '079', '66') INSERT INTO [dbo].[T2] VALUES ( '080', '66') INSERT INTO [dbo].[T2] VALUES ( '081', '66') INSERT INTO [dbo].[T2] VALUES ( '082', '66') INSERT INTO [dbo].[T2] VALUES ( '083', '66') INSERT INTO [dbo].[T2] VALUES ( '084', '66') INSERT INTO [dbo].[T2] VALUES ( '085', '66') INSERT INTO [dbo].[T2] VALUES ( '086', '66') INSERT INTO [dbo].[T2] VALUES ( '087', '66') INSERT INTO [dbo].[T2] VALUES ( '088', '66') INSERT INTO [dbo].[T2] VALUES ( '089', '77') INSERT INTO [dbo].[T2] VALUES ( '090', '77') INSERT INTO [dbo].[T2] VALUES ( '091', '66') INSERT INTO [dbo].[T2] VALUES ( '092', '11') INSERT INTO [dbo].[T2] VALUES ( '093', '88') INSERT INTO [dbo].[T2] VALUES ( '094', '88') INSERT INTO [dbo].[T2] VALUES ( '095', '44') INSERT INTO [dbo].[T2] VALUES ( '096', '66') INSERT INTO [dbo].[T2] VALUES ( '097', '77') INSERT INTO [dbo].[T2] VALUES ( '098', '44') INSERT INTO [dbo].[T2] VALUES ( '099', '77') INSERT INTO [dbo].[T2] VALUES ( '100', '77') INSERT INTO [dbo].[T2] VALUES ( '101', '88') INSERT INTO [dbo].[T2] VALUES ( '102', '88') INSERT INTO [dbo].[T2] VALUES ( '103', '88') INSERT INTO [dbo].[T2] VALUES ( '104', '77') INSERT INTO [dbo].[T2] VALUES ( '105', '66') INSERT INTO [dbo].[T2] VALUES ( '106', '77') INSERT INTO [dbo].[T2] VALUES ( '107', '88') INSERT INTO [dbo].[T2] VALUES ( '108', '88') INSERT INTO [dbo].[T2] VALUES ( '109', '11') INSERT INTO [dbo].[M2] VALUES ( '11', 'A') INSERT INTO [dbo].[M2] VALUES ( '22', 'B') INSERT INTO [dbo].[M2] VALUES ( '33', 'C') INSERT INTO [dbo].[M2] VALUES ( '44', 'D') INSERT INTO [dbo].[M2] VALUES ( '55', 'E') INSERT INTO [dbo].[M2] VALUES ( '66', 'F') INSERT INTO [dbo].[M2] VALUES ( '77', 'G') INSERT INTO [dbo].[M2] VALUES ( '88', 'H') -------------------------------------------------------- -- Aローカルへリンクサーバーを張って以下のクエリを流す。 -------------------------------------------------------- WITH WK_CTE ( [コード1] , [コード2] , [区分] ) AS ( SELECT CODE [コード1] , '' [コード2] , '0' [区分] FROM [127.0.0.1\SQL2005].[AAA].dbo.T2 UNION ALL SELECT '' [コード1] , '' [コード2] , '1' [区分] FROM [127.0.0.1\SQL2005].[AAA].dbo.T2 where 1=0 ) ,WK2 AS ( SELECT [コード1] as [コード1] ,CASE WHEN [区分] = '0' THEN SUBSTRING(WK_CTE.[コード1],1,1) ELSE '' END AS [コード1前半] ,CASE WHEN [区分] = '0' THEN SUBSTRING(WK_CTE.[コード1],2,1) ELSE '' END AS [コード1後半] ,CASE WHEN [区分] = '0' THEN ISNULL(( SELECT M2_R.CODE FROM [127.0.0.1\SQL2005].[AAA].dbo.M2 AS M2_R WHERE M2_R.CODE = WK_CTE.[コード1] ),'') ELSE '' END AS [コード1コード] ,CASE WHEN [区分] = '0' THEN ISNULL(( SELECT M2_R.[NAME] FROM [127.0.0.1\SQL2005].[AAA].dbo.M2 AS M2_R WHERE M2_R.CODE = WK_CTE.[コード1] ),'') ELSE '' END AS [コード1名] FROM WK_CTE ) select * from WK2 where [コード1前半] = '7' and [コード1後半] = '7' ---------------------------------- [結果] ---------------------------------- 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 77 G 77 7 7 66 F ←存在しないはずの行が現れる! 77 7 7 66 F ←存在しないはずの行が現れる! | ||||
|
投稿日時: 2008-02-27 22:54
上記の構文を打った場合、どのホスト端末で処理が実行されるんですか? 『127.0.0.1』は自分自身ですよね。 127.0.0.1が自動的にホスト名又は既存のネットワークアドレスに 変わっていれば問題ないとは思いますが、 ホスト名又は既存のネットワークアドレスに変わってなければ問題 が発生する可能性はあるかと・・・・ | ||||
|
投稿日時: 2008-02-27 23:16
今回の例は端末一台でネットワーク接続なしの環境でも試せるように
自分自身に対してリンクを張っていますが、 当然、自分のIPアドレスを直接指定してリンクサーバーを設定した際も、 別のSQLSERVERに対してリンクサーバーを設定しても同じ現象が発生します。 また、データ量が増えるほどこの現象の発生する頻度が高くなるようで、 数万件のデータより数百件を抽出した際には、半分以上がデタラメなデータに なってしまいました。 [ メッセージ編集済み 編集者: ハニワ祭り 編集日時 2008-02-27 23:37 ] | ||||
|
投稿日時: 2008-02-28 10:55
ハニワ祭りさんの提示されたデータおよびスクリプトを用いて不具合事象が再現することを追試できました。(SQL Server 2005 SP2 GDR 9.0.3159)
上総さんは、ハニワ祭りさんの提示している内容を追試したのでしょうか? 追試もせずに「まさかバグのはずはない」「他の書き方してみたら」と思っているのなら口出しせずに黙っていて欲しい。邪魔だから。 SQL Server のいままでのリリースノートを見ていれば分かることですが、SQL Server は完全無欠ではありません。ほとんど毎回、リリースノートには「誤った結果セットを返すことがあった」というデータベースにあるまじき不具合が記載されています。 ハニワ祭りさんはどうしますか? この事象をマイクロソフトに投げてもらって、不具合を修正してもらいたいと私は考えています。ハニワ祭りさんが手間なら私のほうからマイクロソフトに投げても構いません。 最後に私が追試過程でまとめたスクリプトを載せておきます。ハニワ祭りさんのスクリプトからデータ量を減らしたり、複雑な共通テーブル式を除去してみました。(が、ちゃんと不具合は再現するスクリプトです。) 追試が面倒だという方のために、リンクサーバーの作成、後片付けもすべてスクリプトに含めておきました。SQL Server 2005 の累積パッチを当てている方、SQL Server 2008 CTP を入れている方にも動作を確認していただけるとありがたいです。
|
1|2|3|4|5
次のページへ»