関連する3つのテーブルがある次の例を考えてみましょう。Orders、Users、およびOrderDetails。OrderDetailsは、外部キーを使用してOrdersテーブルとUsersテーブルにリンクされます。これは、本質的にリレーショナルデータベースの非常に典型的なセットアップです。おそらく、リレーショナル DBMSの全体的な目的です。
USE tempdb;
IF OBJECT_ID(N'dbo.OrderDetails', N'U') IS NOT NULL
DROP TABLE dbo.OrderDetails;
IF OBJECT_ID(N'dbo.Orders', N'U') IS NOT NULL
DROP TABLE dbo.Orders;
IF OBJECT_ID(N'dbo.Users', N'U') IS NOT NULL
DROP TABLE dbo.Users;
CREATE TABLE dbo.Orders
(
OrderID int NOT NULL
CONSTRAINT OrderTestPK
PRIMARY KEY
CLUSTERED
, SomeOrderData varchar(1000)
CONSTRAINT Orders_somedata_df
DEFAULT (CRYPT_GEN_RANDOM(1000))
);
CREATE TABLE dbo.Users
(
UserID int NOT NULL
CONSTRAINT UsersPK
PRIMARY KEY
CLUSTERED
, SomeUserData varchar(1000)
CONSTRAINT Users_somedata_df
DEFAULT (CRYPT_GEN_RANDOM(1000))
);
CREATE TABLE dbo.OrderDetails
(
OrderDetailsID int NOT NULL
CONSTRAINT OrderDetailsTestPK
PRIMARY KEY
CLUSTERED
, OrderID int NOT NULL
CONSTRAINT OrderDetailsOrderID
FOREIGN KEY
REFERENCES dbo.Orders(OrderID)
, UserID int NOT NULL
CONSTRAINT OrderDetailsUserID
FOREIGN KEY
REFERENCES dbo.Users(UserID)
, SomeOrderDetailsData varchar(1000)
CONSTRAINT OrderDetails_somedata_df
DEFAULT (CRYPT_GEN_RANDOM(1000))
);
INSERT INTO dbo.Orders (OrderID)
SELECT TOP(100) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.syscolumns sc;
INSERT INTO dbo.Users (UserID)
SELECT TOP(100) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.syscolumns sc;
INSERT INTO dbo.OrderDetails (OrderDetailsID, OrderID, UserID)
SELECT TOP(10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
, o.OrderID
, u.UserID
FROM sys.syscolumns sc
CROSS JOIN dbo.Orders o
CROSS JOIN dbo.Users u
ORDER BY NEWID();
CREATE INDEX OrderDetailsOrderID ON dbo.OrderDetails(OrderID);
CREATE INDEX OrderDetailsUserID ON dbo.OrderDetails(UserID);
ここでは、UserIDが15であるOrderDetailsテーブルを照会しています。
SELECT od.OrderDetailsID
, o.OrderID
, u.UserID
FROM dbo.OrderDetails od
INNER JOIN dbo.Users u ON u.UserID = od.UserID
INNER JOIN dbo.Orders o ON od.OrderID = o.OrderID
WHERE u.UserID = 15
クエリからの出力は次のようになります。
╔================╦========╦========╗
║OrderDetailsID║OrderID║UserID║
╠================╬========╬========╣
║2200115║2║15║
630 630215║3║15║
║1990215║3║15║
║4960215║3║15║
║100715║8║15║
║3930815║9║15║
║6310815║9║15║
║4441015║11║15║
║2171315║14║15║
║3431415║15║15║
║4571415║15║15║
║6421515║16║15║
║2271715║18║15║
║2601715║18║15║
║3521715║18║15║
║221815║19║15║
║3381915║20║15║
║4471915║20║15║
╚================╩========╩========╝
ご覧のように、行の出力順序はOrderDetailsテーブルの行の順序と一致しません。
明示的なORDER BY
行を追加すると、行が目的の順序でクライアントに返されます。
SELECT od.OrderDetailsID
, o.OrderID
, u.UserID
FROM dbo.OrderDetails od
INNER JOIN dbo.Users u ON u.UserID = od.UserID
INNER JOIN dbo.Orders o ON od.OrderID = o.OrderID
WHERE u.UserID = 15
ORDER BY od.OrderDetailsID;
╔================╦========╦========╗
║OrderDetailsID║OrderID║UserID║
╠================╬========╬========╣
║3915║40║15║
║100715║8║15║
║221815║19║15║
║299915║100║15║
368 368215║83║15║
603 603815║39║15║
630 630215║3║15║
728 728515║86║15║
972 972215║23║15║
║992015║21║15║
║1017115║72║15║
║1113815║39║15║
╚================╩========╩========╝
行の順序が不可欠である、とあなたのエンジニアはその順序が不可欠であることがわかっている場合、彼らは今まで必要がありますしたい使用することをORDER BY
間違ったために関連する障害が発生した場合、それはそれらに彼らの指定を要する可能性があるため、文を。
OrderDetails
上記のテーブルを使用した、おそらくより有益な2番目の例では、他のテーブルは結合しませんが、OrderIDとUserIDの両方に一致する行を検索する簡単な要件があるため、問題が発生します。
クエリをサポートするためにインデックスを作成します。これは、パフォーマンスが何らかの形で重要な場合(実際にそうでない場合)に実際に行う可能性が高いためです。
CREATE INDEX OrderDetailsOrderIDUserID ON dbo.OrderDetails(OrderID, UserID);
クエリは次のとおりです。
SELECT od.OrderDetailsID
FROM dbo.OrderDetails od
WHERE od.OrderID = 15
AND (od.UserID = 21 OR od.UserID = 22)
そして結果:
================╗
║OrderDetailsID║
================╣
║21421║
║5061421║
║7091421║
║691422║
║3471422║
║7241422║
================╝
ORDER BY
句を追加すると、ここでも正しい並べ替えを確実に取得できます。
これらのモックアップは単純な例であり、明示的なORDER BY
ステートメントがない場合、行が「順序どおり」になることは保証されません。このような例は他にもたくさんあり、DBMSエンジンのコードは頻繁に変更されるため、特定の動作は時間とともに変化する可能性があります。