TimberLandChapelのTech Blog

TimberLandChapel が提供する技術Tips,思いつきメモ,雑感ブログです。
Office 互換リボン Release 1.0 をリリースしました。

購読

今期のアンケート

INETAJ

Microsoft

SQL Server

TLC.com

クリエイティブ・コモンズ

情報処理関係官公庁

【SQL Server 2005】状況を確認して対策を立てる
シナリオと要件

クエリがなぜおかしな結果を返してしまうのか? の原因を探って対策を考えます。

この記事は,
SQL Server 2005 Developer Edition
に基づいて記述しています。

実行プランの確認

まずは実行プランを確認してみましょう。
[SQL Server 2005] で実行プランを表示させるためには,以下の手順に従います。

[SQL Server Management Studio] で新しいクエリを作成して,問題のクエリを貼り付ける。

メニューから [クエリ] > [実際の実行プランを含める] をクリックする。

クエリを実行する。

[メニュー] 左のアイコンが枠線で囲まれた状態になったならば,[結果ペイン] の [実行プラン] タブに実行プランが表示されます。

今回の実行プランは次のようになっているはずです。
※ 環境によって実行プランは変化することがあります。

SQL Server 2000 での実行プラン

今回のプランの比較対象として,[SQL Server 2000] で同じようなクエリを実行した際の実行プランを見て見ましょう。

SQL Server 2000 での実験
/*
2005.12.24 TimberLandChapel
Self Join Test SQL Server 2000 / SQL Server 2005 for 2000
*/
USE JoinTest
 
--Table Drop Section
IF EXISTS (SELECT * FROM sysobjects WHERE object_id =
OBJECT_ID(N'[dbo].[JoinTest]') AND type in (N'U'))
DROP TABLE [dbo].[JoinTest]
GO
 
--Test Table Create
CREATE TABLE [dbo].[JoinTest](
[Column1] [nvarchar](50) COLLATE Japanese_CI_AS NULL,
[Column2] [nvarchar](50) COLLATE Japanese_CI_AS NULL,
[Column3] [nvarchar](50) COLLATE Japanese_CI_AS NULL
) ON [PRIMARY]
GO
 
--Test Data Insert
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A001','1','100')
 
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A001','2','-100')
 
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A001','3','100')
 
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A002','1','100')
 
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A002','2','-100')
 
INSERT INTO [dbo].[JoinTest] ([Column1],[Column2],[Column3])
    VALUES ('A002','3','-100')
GO
 
--Show Test Table
SELECT * FROM [JoinTest]
GO
 
--With Max Query
--This query returns false result.
SELECT * FROM
((SELECT [Column1], Max(Column2) AS [MaxColumn2] FROM
[dbo].[JoinTEST] WHERE [Column3] < 0 GROUP BY [Column1]) AS [TABLE1]
INNER JOIN
(SELECT [Column1], Max(Column2) AS [MaxColumn2] FROM [dbo].[JoinTEST]
GROUP BY [Column1]) AS [TABLE2]
ON
[TABLE1].[Column1] = [TABLE2].[Column1]
AND [TABLE1].[MaxColumn2] = [TABLE2].[MaxColumn2])
GO

実行プランは以下のようになるはずです。
※ 環境によって実行プランは変化することがあります。

結果の考察




Table Scan の違い



[SQL Server 2000] は2つのテーブルスキャンが発生しているにも関わらず,
[SQL Server 2005] では1つしかスキャンしていないようです。




Sort,Stream Aggregate



[Column1] に対する処理を行っており,スキャンされたテーブルに対してそれぞれ行っています。




Marge Join vs Filter..Segment..TOP???



[SQL Server 2000] における [Marge Join] はインデックスが効かない場合の正常な動作です。
一方,
[SQL Server 2005] の動作はやはりおかしな動きをしているようです。

対策を考える




2005 はクエリの解釈に失敗している?



実行プランを比較すると,どうも [SQL Server 2005] はクエリオプティマイザが効率化解釈を失敗しているのではないかということが思いつきます。
このことから,


クエリオプティマイザに実行プランの解釈を変えてもらいましょう



という発想に結びつきます。
問題のクエリの書き振りを変えてみて,結果がどうなるかを実験していくことになります。

Published 2006年5月10日 0:28 投稿者 timberlandchapel

コメント

コメントはありません