SELECT 実行時に ORDER BY を指定しないと、どういう並び順になるか?というのを試してみました。
※ORDER BY を指定しない場合、並び順は保障されなかったと思います。並び順を意識する必要がある場合は、ORDER BY を指定してください。
試した環境は、Microsoft SQL Server 2008 R2 (CTP) - 10.50.1352.12 (X64) です。
実験内容:以下の三つのテーブルを作成し、SELECT * FROM <テーブル名> を実行しました。
全てのテーブルは、Id, No, Name の3列からなり、Id が IDENTITY 指定の PK です。
Table_1:PK(Id 列) が クラスタ化インデックス
Table_2:PK 以外(No 列)にクラスタ化インデックス
Table_3:クラスタ化インデックスは無し
この時、実行結果は、
1.Table_1:PK (クラスタ化インデックス)で並ぶ
2.Table_2:クラスタ化インデックスで並ぶ
3.Table_3:INSERT した順に並ぶ
4.Table_3にクラスタ化インデックス(No列)を指定して再度 SELECT を実行すると、2.と同じ結果になる。
となりました。
クエリ
USE [Test] GO CREATE TABLE [Table_1]( [Id] [int] IDENTITY(1,1) NOT NULL, [No] [int] NOT NULL, [Name] [nvarchar](10) NOT NULL, CONSTRAINT [PK_Table_1] PRIMARY KEY CLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO SET IDENTITY_INSERT [Table_1] ON INSERT [Table_1] ([Id], [No], [Name]) VALUES (2, 9, N'BBB') INSERT [Table_1] ([Id], [No], [Name]) VALUES (5, 6, N'EEE') INSERT [Table_1] ([Id], [No], [Name]) VALUES (4, 7, N'DDD') INSERT [Table_1] ([Id], [No], [Name]) VALUES (3, 8, N'CCC') INSERT [Table_1] ([Id], [No], [Name]) VALUES (1, 10, N'AAA') SET IDENTITY_INSERT [Table_1] OFF GO CREATE TABLE [Table_2]( [Id] [int] IDENTITY(1,1) NOT NULL, [No] [int] NOT NULL, [Name] [nvarchar](10) NOT NULL, CONSTRAINT [PK_Table_2] PRIMARY KEY NONCLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO CREATE CLUSTERED INDEX [IX_Table_2] ON [Table_2] ( [No] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO SET IDENTITY_INSERT [Table_2] ON INSERT [Table_2] ([Id], [No], [Name]) VALUES (2, 9, N'BBB') INSERT [Table_2] ([Id], [No], [Name]) VALUES (5, 6, N'EEE') INSERT [Table_2] ([Id], [No], [Name]) VALUES (4, 7, N'DDD') INSERT [Table_2] ([Id], [No], [Name]) VALUES (3, 8, N'CCC') INSERT [Table_2] ([Id], [No], [Name]) VALUES (1, 10, N'AAA') SET IDENTITY_INSERT [Table_2] OFF GO CREATE TABLE [Table_3]( [Id] [int] IDENTITY(1,1) NOT NULL, [No] [int] NOT NULL, [Name] [nvarchar](10) NOT NULL, CONSTRAINT [PK_Table_3] PRIMARY KEY NONCLUSTERED ( [Id] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO GO SET IDENTITY_INSERT [Table_3] ON INSERT [Table_3] ([Id], [No], [Name]) VALUES (2, 9, N'BBB') INSERT [Table_3] ([Id], [No], [Name]) VALUES (5, 6, N'EEE') INSERT [Table_3] ([Id], [No], [Name]) VALUES (4, 7, N'DDD') INSERT [Table_3] ([Id], [No], [Name]) VALUES (3, 8, N'CCC') INSERT [Table_3] ([Id], [No], [Name]) VALUES (1, 10, N'AAA') SET IDENTITY_INSERT [Table_3] OFF GO SELECT * FROM [Table_1] SELECT * FROM [Table_2] SELECT * FROM [Table_3] CREATE CLUSTERED INDEX [IX_Table_3] ON [Table_3] ( [No] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] GO SELECT * FROM [Table_3] DROP TABLE [Table_3] DROP TABLE [Table_2] DROP TABLE [Table_1] GO
実行結果
クラスタ化インデックスが指定されていると、クラスタ化インデックスで並ぶはずです。
テーブルとインデックスの編成 から引用
クラスタ化テーブル (クラスタ化インデックスのあるテーブル) データ行は、クラスタ化インデックス キーに基づく順序で格納されます。クラスタ化インデックスは、クラスタ化インデックス キーの値を基にした B ツリー インデックス構造として実装されているので、行を高速に取得できます。インデックスの各レベルのページは、リーフ レベルであるデータ ページも含め、二重リンク リストにリンクされます。ただし、あるレベルから別のレベルへ移動する際は、キー値が使用されます。詳細については、「クラスタ化インデックスの構造」を参照してください。
但し、クラスタ化インデックスに 複数列を指定した場合は列の指定順で並び方が変わるのかな?
まあ、並び順を考慮する必要があるなら ORDER BY を指定しとけって事です。
※この記事を書いた理由
ORDER BY を指定せずに実行した SELECT の結果は、インデックスの設定変更等によって並び順が変わるよっていうのを書きたかったんです。
既存のアプリに対して、パフォーマンスチューニング等で クラスタ化インデックスを変更すると SELECT の実行結果が変わる可能性があるので、ユーザーが見えるデータに対しては ORDER BY を明示的に指定しましょうねと。