/* 04. 페이지 처리 */
USE jwjung
GO
IF OBJECT_ID('Orders') IS NOT NULL
DROP TABLE Orders
GO
SELECT TOP 0 * INTO Orders FROM Northwind.dbo.Orders
GO
INSERT INTO Orders
SELECT a.CustomerID, a.EmployeeID, a.OrderDate, a.RequiredDate
, a.ShippedDate, a.ShipVia, a.Freight, a.ShipName, a.ShipAddress
, a.ShipCity, a.ShipRegion, a.ShipPostalCode, a.ShipCountry
FROM Northwind.dbo.Orders a
, (SELECT TOP 10 * FROM Northwind.dbo.Orders) b
GO
--8300
ALTER TABLE Orders ADD CONSTRAINT Orders_pk PRIMARY KEY NONCLUSTERED (OrderID)
GO
CREATE NONCLUSTERED INDEX Orders_x01 ON Orders (CustomerID, OrderDate, OrderID)
GO
EXEC sp_helpindex 'Orders';
SET STATISTICS PROFILE ON
SET STATISTICS TIME ON
SET STATISTICS IO ON
--(1) 앞쪽 페이지를 주로 조회할 때
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
ORDER BY OrderDate, OrderID
GO
--Rows Executes StmtText
--11 1 SELECT TOP 11 * FROM Orders WHERE
CustomerID = 'QUICK' ORDER BY OrderDate, OrderID
--11 1
|--Top(TOP EXPRESSION:((11)))
--11 1
|--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000], [Expr1005])
WITH ORDERED PREFETCH)
--216 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK') ORDERED FORWARD)
--11 11 |--RID Lookup(OBJECT:([jwjung].[dbo].[Orders]),
SEEK:([Bmk1000]=[Bmk1000]) LOOKUP ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 14, 물리적 읽기 수 2, 미리 읽기 수 216, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
--두번째 페이지 (21건 = 2 * 10 + 1) - 11(뒷쪽11건)
SELECT TOP 11 *
FROM (
SELECT TOP 21 *
, ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) AS rnum
FROM Orders
WHERE CustomerID = 'QUICK'
ORDER BY OrderDate, OrderID
) a
WHERE a.rnum >= 11
ORDER BY a.OrderDate, a.OrderID
GO
--Rows Executes StmtText
--11 1 SELECT TOP 11 * FROM ( SELECT TOP 21 * , ROW_NUMBER() OVER(ORDER BY
OrderDate, OrderID) AS rnum FROM Orders WHERE CustomerID = 'QUICK' ORDER BY
OrderDate, OrderID ) a WHERE a.rnum
>= 11 ORDER BY a.OrderDate, a.OrderID
--11 1
|--Top(TOP EXPRESSION:((11)))
--11 1
|--Filter(WHERE:([Expr1004]>=(11)))
--21 1 |--Top(TOP EXPRESSION:((21)))
--21 1 |--Sequence
Project(DEFINE:([Expr1004]=row_number))
--21 1 |--Segment
--21 1 |--Nested Loops(Inner Join, OUTER
REFERENCES:([Bmk1000], [Expr1006]) WITH ORDERED PREFETCH)
--21 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK') ORDERED FORWARD)
--21 21 |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 23, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
--SQL 2005이상
DECLARE @페이지번호 INT, @페이지별로우수
INT
SET @페이지번호 = 2
SET @페이지별로우수 = 10
SELECT TOP (@페이지별로우수 + 1) *
FROM (
SELECT TOP (@페이지번호 * @페이지별로우수 + 1)
*
, ROW_NUMBER() OVER (ORDER BY OrderDate, OrderID) AS rnum
FROM Orders WITH (INDEX(Orders_x01))
WHERE CustomerID = 'QUICK'
ORDER BY OrderDate, OrderID
) a
WHERE a.rnum >= (@페이지번호 - 1) *
@페이지별로우수
+ 1
ORDER BY a.OrderDate, a.OrderID
GO
--Rows Executes StmtText
--11 1 SELECT TOP (@페이지별로우수 + 1) * FROM ( SELECT TOP (@페이지번호 * @페이지별로우수 + 1) * , ROW_NUMBER() OVER
(ORDER BY OrderDate, OrderID) AS rnum FROM Orders WITH (INDEX(Orders_x01))
WHERE CustomerID = 'QUICK' ORDER BY OrderDate, OrderID) a WHERE a.rnum >= (@페이지번호 - 1) * @페이지별로우수 + 1 ORDER BY a.OrderDate,
a.OrderID
--11 1
|--Top(TOP EXPRESSION:(CONVERT_IMPLICIT(bigint,[@페이지별로우수]+(1),0)))
--11 1
|--Filter(WHERE:([Expr1004]>=CONVERT_IMPLICIT(bigint,([@페이지번호]-(1))*[@페이지별로우수]+(1),0)))
--21 1 |--Top(TOP
EXPRESSION:(CONVERT_IMPLICIT(bigint,[@페이지번호]*[@페이지별로우수]+(1),0)))
--21 1 |--Sequence
Project(DEFINE:([Expr1004]=row_number))
--21 1 |--Segment
--21 1 |--Nested
Loops(Inner Join, OUTER REFERENCES:([Bmk1000], [Expr1009]) WITH ORDERED
PREFETCH)
--21 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK') ORDERED FORWARD)
--21 21 |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 23, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
--SQL Server 2000
DECLARE @페이지번호 INT, @페이지별로우수
INT
SET @페이지번호 = 2
SET @페이지별로우수 = 10
SELECT *
FROM (
SELECT TOP (@페이지별로우수 + 1) *
FROM (
SELECT TOP (@페이지번호 * @페이지별로우수 + 1)
*
FROM Orders WITH (INDEX(Orders_x01))
WHERE CustomerID = 'QUICK'
ORDER BY OrderDate, OrderID
) a
ORDER BY a.OrderDate DESC, a.OrderID DESC
) a
ORDER BY a.OrderDate, a.OrderID
GO
--위의 두 쿼리는 뒤쪽 페이지로 이동할수록 성능이 나빠진다.
--만약 100번째 페이지를 조회하면, 파생 테이블에서 1,001(=100*10+1) 건을 추출하고서 990(=1,000-11)건을
버리게 된다.
--페이지 번호가 임계치를 넘어가면 (인덱스에서 테이블로의 랜덤 액세스 때문에) 테이블을 전체 스캔하는 것보다 더 많은 페이지 I/O를 일으킬 수
있다.
--(2) 뒤쪽 페이지도 자주 조회할 때
--첫번째 페이지
SELECT TOP 11
ROW_NUMBER() OVER(ORDER BY OrderDate, OrderID) as rnum, *
FROM Orders
WHERE CustomerID = 'QUICK'
ORDER BY OrderDate, OrderID
GO
--두번째 페이지
SELECT TOP 11
ROW_NUMBER() OVER (ORDER BY OrderDate, OrderID) as rnum, *
FROM Orders
WHERE CustomerID = 'QUICK'
/* 앞 페이지의 마지막
데이터보다 크거나 같아야 한다 */
AND ((OrderDate = CONVERT(DATETIME, '19960820', 112) AND OrderID >= 38)
OR OrderDate > CONVERT(DATETIME, '19960820', 112))
ORDER BY OrderDate, OrderID
GO
/* 추가 1건(화면에는 실제로 10건만 출력된다)은 다음 페이지가 더 있는지 확인하는 용도뿐만 아니라
다음 페이지의 시작점이 되기도 한다.
글자 그대로 일거양득의 효과를 나타낸다. 이번
절의 서두에서 언급했듯이, 위 쿼리처럼 특정 시작점을 이용해 페이지 처리를 하려면 각 로우가(유일하게)
구별되어야 한다. Orders 테이블에는 [CustomerID + OrderDate] 컬럼 조합으로 여러 건이 있으므로
order by 조건에 OrderID 컬럼을 추가했다.
*/
--첫번째 페이지용 쿼리와 두번째 이상 페이지용 쿼리를 합할 수 있다
DECLARE @OrderDate CHAR(8), @OrderID INT --앞 페이지의 11번째 데이터 저장용 변수
SET @OrderDate = '19960820' --OrderDate 컬럼에는 날짜 값만 들어 있어서 CHAR(8) 형식으로 처리했음
SET @OrderID = 38
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
/* 앞 페이지의 마지막
데이터보다 크거나 같아야 한다 */
AND ((OrderDate = CONVERT(DATETIME, @OrderDate, 112) AND OrderID >= @OrderID)
OR OrderDate > CONVERT(DATETIME, @OrderDate, 112))
ORDER BY OrderDate, OrderID
GO
--Rows Executes StmtText
--11 1 SELECT TOP 11 * FROM Orders WHERE
CustomerID = 'QUICK' /* 앞 페이지의 마지막 데이터보다 크거나 같아야 한다
*/ AND ((OrderDate = CONVERT(DATETIME, @OrderDate, 112) AND OrderID >=
@OrderID) OR OrderDate > CONVERT(DATETIME, @OrderDate, 112)) ORDER BY
OrderDate, OrderID
--11 1
|--Top(TOP EXPRESSION:((11)))
--11 1
|--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000], [Expr1007])
WITH ORDERED PREFETCH)
--11 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK'),
WHERE:([jwjung].[dbo].[Orders].[OrderDate]=CONVERT(datetime,[@OrderDate],112)
AND [jwjung].[dbo].[Orders].[OrderID]>=[@OrderID] OR
[jwjung].[dbo].[Orders].[OrderDate]>CONVERT(datetime,[@OrderDate],112))
ORDERED FORWARD)
--11 11
|--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 13, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
/*위 쿼리의 실행계획을 살펴보니 뭔가 이상하다. Index Seek 오퍼레이션을 자세히 보면, [CustomerID] = N'QUICK' 조건만 SEEK:() 부분에
있고
페이지 처리용 조건은 모두 WHERE:() 부분에
나타났다. 이렇게 되면 'QUICK' 조건만 Orders_x01 인덱스의 액세스 범위를 결정하고 정작 페이지 처리에
꼭 필요한 나머지 조건은 필터링 역할 밖에 하지 못한다. */
--인덱스 최적으로 액세스하도록 하려면 쿼리를 변경해야 한다.
DECLARE @OrderDate CHAR(8), @OrderID INT --앞 페이지의 11번째 데이터 저장용 변수
SET @OrderDate = '19960820'
SET @OrderID = 38
SELECT TOP 11 *
FROM (
SELECT *
FROM (
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
/* 앞 페이지의 마지막
데이터와 같음 */
AND OrderDate = CONVERT(DATETIME, @OrderDate, 112)
AND OrderID >= @OrderID
ORDER BY OrderDate, OrderID
) a
UNION ALL
SELECT *
FROM (
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
/* 앞 페이지의 마지막
데이터보다 큼 */
AND OrderDate > CONVERT(DATETIME, @OrderDate, 112)
ORDER BY OrderDate, OrderID
) a
) a
ORDER BY OrderDate, OrderID
GO
--Rows Executes StmtText
--11 1 SELECT TOP 11 * FROM ( SELECT * FROM ( SELECT
TOP 11 * FROM Orders WHERE CustomerID =
'QUICK' /* 앞 페이지의 마지막 데이터와 같음 */ AND
OrderDate = CONVERT(DATETIME, @OrderDate, 112) AND OrderID >= @OrderID ORDER
BY OrderDate, OrderID) a UNION ALL SELECT * FROM ( SELECT TOP 11 * FROM
Orders WHERE CustomerID = 'QUICK' /*
앞 페이지의 마지막 데이터보다 큼 */ AND
OrderDate > CONVERT(DATETIME, @OrderDate, 112) ORDER BY OrderDate, OrderID ) a )
a ORDER BY OrderDate, OrderID
--11 1
|--Top(TOP EXPRESSION:((11)))
--11 1
|--Merge Join(Concatenation)
--10 1 |--Top(TOP EXPRESSION:((11)))
--10 1 |
|--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1000]))
--10 1 | |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK' AND
[jwjung].[dbo].[Orders].[OrderDate]=CONVERT(datetime,[@OrderDate],112) AND
[jwjung].[dbo].[Orders].[OrderID] >= [@OrderID]) ORDERED FORWARD)
--10 10 | |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--1 1 |--Top(TOP EXPRESSION:((11)))
--1 1 |--Nested Loops(Inner Join,
OUTER REFERENCES:([Bmk1004], [Expr1025]) WITH ORDERED PREFETCH)
--1 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK' AND
[jwjung].[dbo].[Orders].[OrderDate] > CONVERT(datetime,[@OrderDate],112))
ORDERED FORWARD)
--1 1 |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1004]=[Bmk1004]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 2, 논리적 읽기
수 15, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
--논리적 읽기 수가 13에서 15로 늘어난 탓에 오히려
성능이 떨어진 것처럼 보이지만, 조건에 해당하는 데이터가 워낙 적어서
union all 에 의해 수치가 왜곡되어 보이는 것 뿐이다.
--앞쪽 페이지로 거슬러 올라갈 때
/* 뒤 페이지의 첫 번째 데이터 저장용 변수 */
DECLARE @OrderDate CHAR(8), @OrderID INT
/* OrderDate 컬럼은 날짜 값만 관리하므로 편의상 CHAR(8) 형식으로 받아왔음 */
SET @OrderDate = '19960820'
SET @OrderID = 38
SELECT *
FROM (
SELECT TOP 11 *
FROM (
SELECT *
FROM (
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
--뒤 페이지의 첫
번째 데이터와 같음
AND OrderDate = CONVERT(DATETIME, @OrderDate, 112)
AND OrderID <= @OrderID
ORDER BY OrderDate DESC, OrderID DESC
) a
UNION ALL
SELECT *
FROM (
SELECT TOP 11 *
FROM Orders
WHERE CustomerID = 'QUICK'
--뒤 페이지의 첫
번째 데이터보다 작음
AND OrderDate < CONVERT(DATETIME, @OrderDate, 112)
ORDER BY OrderDate DESC, OrderID DESC
) a
) a
ORDER BY OrderDate DESC, OrderID DESC
) a
ORDER BY OrderDate, OrderID
GO
--Rows Executes StmtText
--11 1 SELECT * FROM (SELECT TOP 11 * FROM
(SELECT * FROM ( SELECT TOP 11
* FROM Orders WHERE CustomerID = 'QUICK' /*
뒤 페이지의 첫 번째 데이터와 같음 */ AND OrderDate = CONVERT(DATETIME,
@OrderDate, 112) AND OrderID <= @OrderID ORDER BY OrderDate DESC, OrderID
DESC ) a UNION ALL SELECT * FROM
(SELECT TOP 11 * FROM Orders
WHERE CustomerID = 'QUICK' /* 뒤 페이지의 첫 번째 데이터보다 작음 */
AND OrderDate < CONVERT(DATETIME, @OrderDate, 112) ORDER BY OrderDate DESC,
OrderID DESC) a ) a ORDER BY
OrderDate DESC, OrderID DESC ) a ORDER BY OrderDate, OrderID
--11 1
|--Sort(ORDER BY:([Union1011] ASC, [Union1008] ASC))
--11 1
|--Top(TOP EXPRESSION:((11)))
--11 1 |--Merge Join(Concatenation)
--1 1 |--Top(TOP EXPRESSION:((11)))
--1 1 | |--Nested Loops(Inner Join, OUTER
REFERENCES:([Bmk1000]))
--1 1 | |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]),
SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK' AND
[jwjung].[dbo].[Orders].[OrderDate]=CONVERT(datetime,[@OrderDate],112) AND
[jwjung].[dbo].[Orders].[OrderID] <= [@OrderID]) ORDERED BACKWARD)
--1 1 | |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--10 1 |--Top(TOP EXPRESSION:((11)))
--10 1 |--Nested Loops(Inner
Join, OUTER REFERENCES:([Bmk1004], [Expr1025]) WITH ORDERED PREFETCH)
--10 1 |--Index
Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]), SEEK:([jwjung].[dbo].[Orders].[CustomerID]=N'QUICK'
AND [jwjung].[dbo].[Orders].[OrderDate] <
CONVERT(datetime,[@OrderDate],112)) ORDERED BACKWARD)
--10 10 |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1004]=[Bmk1004]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 2, 논리적 읽기
수 15, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
--(3) 적절한 인덱스가 없어서 정렬이 불가피할 때
--Orders 테이블의 Orders_x01 인덱스는 [CustomerID
+ OrderDate + OrderID] 컬럼으로 구성되어 있다.
--한번에 10건씩 보여주는 화면에서 10번째 페이지를
조회하는 쿼리
SELECT *
FROM (
SELECT TOP 11 *
FROM (
SELECT TOP 101 *
FROM Orders
ORDER BY OrderDate, OrderID
) a
ORDER BY a.OrderDate DESC, a.OrderID DESC
) a
ORDER BY a.OrderDate, a.OrderID
GO
--Rows Executes StmtText
--11 1 SELECT * FROM ( SELECT TOP 11 * FROM ( SELECT TOP 101 * FROM Orders ORDER BY
OrderDate, OrderID) a ORDER BY a.OrderDate DESC, a.OrderID DESC ) a ORDER BY a.OrderDate, a.OrderID
--11 1
|--Sort(ORDER BY:([jwjung].[dbo].[Orders].[OrderDate] ASC, [jwjung].[dbo].[Orders].[OrderID]
ASC))
--11 1
|--Sort(TOP 11, ORDER BY:([jwjung].[dbo].[Orders].[OrderDate] DESC,
[jwjung].[dbo].[Orders].[OrderID] DESC))
--101 1 |--Sort(TOP 101, ORDER
BY:([jwjung].[dbo].[Orders].[OrderDate] ASC, [jwjung].[dbo].[Orders].[OrderID]
ASC))
--8300 1 |--Table
Scan(OBJECT:([jwjung].[dbo].[Orders]))
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 199, 물리적 읽기 수 0, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
SELECT *
FROM (
SELECT TOP 11 *
FROM (
SELECT TOP 101 *
FROM Orders WITH (INDEX(Orders_x01))
ORDER BY OrderDate, OrderID
) a
ORDER BY a.OrderDate DESC, a.OrderID DESC
) a
ORDER BY a.OrderDate, a.OrderID
GO
--Rows Executes StmtText
--11 1 SELECT * FROM (SELECT TOP 11 * FROM
(SELECT TOP 101 * FROM Orders WITH (INDEX(Orders_x01)) ORDER BY OrderDate,
OrderID) a ORDER BY a.OrderDate DESC, a.OrderID DESC ) a ORDER BY a.OrderDate, a.OrderID
--11 1
|--Sort(ORDER BY:([jwjung].[dbo].[Orders].[OrderDate] ASC,
[jwjung].[dbo].[Orders].[OrderID] ASC))
--11 1
|--Sort(TOP 11, ORDER BY:([jwjung].[dbo].[Orders].[OrderDate] DESC,
[jwjung].[dbo].[Orders].[OrderID] DESC))
--101 1 |--Sort(TOP 101, ORDER
BY:([jwjung].[dbo].[Orders].[OrderDate] ASC, [jwjung].[dbo].[Orders].[OrderID]
ASC))
--8300 1 |--Nested Loops(Inner Join,
OUTER REFERENCES:([Bmk1000], [Expr1005]) WITH UNORDERED PREFETCH)
--8300 1 |--Index
Scan(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]))
--8300 8300 |--RID
Lookup(OBJECT:([jwjung].[dbo].[Orders]), SEEK:([Bmk1000]=[Bmk1000]) LOOKUP
ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 8340, 물리적 읽기 수 1, 미리 읽기 수 30, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
SELECT c.*
FROM (
SELECT TOP 11 *
FROM (
SELECT TOP 101 OrderDate, OrderID
FROM Orders
ORDER BY OrderDate, OrderID
) a
ORDER BY a.OrderDate DESC, a.OrderID DESC
) b
, Orders c
WHERE b.OrderID = c.OrderID
ORDER BY b.OrderDate, b.OrderID
OPTION (FORCE ORDER, LOOP
JOIN)
GO
--Rows Executes StmtText
--11 1 SELECT c.* FROM (SELECT TOP 11 * FROM
( SELECT TOP 101 OrderDate,
OrderID FROM Orders ORDER BY OrderDate, OrderID) a ORDER BY a.OrderDate DESC,
a.OrderID DESC ) b, Orders c WHERE
b.OrderID = c.OrderID ORDER BY b.OrderDate, b.OrderID OPTION (FORCE ORDER, LOOP
JOIN)
--11 1
|--Nested Loops(Inner Join, OUTER REFERENCES:([Bmk1004]))
--11 1
|--Nested Loops(Inner Join, OUTER
REFERENCES:([jwjung].[dbo].[Orders].[OrderID]))
--11 1
| |--Sort(ORDER
BY:([jwjung].[dbo].[Orders].[OrderDate] ASC, [jwjung].[dbo].[Orders].[OrderID]
ASC))
--11 1
| | |--Sort(TOP 11, ORDER
BY:([jwjung].[dbo].[Orders].[OrderDate] DESC, [jwjung].[dbo].[Orders].[OrderID]
DESC))
--101 1 |
| |--Sort(TOP 101, ORDER
BY:([jwjung].[dbo].[Orders].[OrderDate] ASC, [jwjung].[dbo].[Orders].[OrderID]
ASC))
--8300 1
| | |--Index
Scan(OBJECT:([jwjung].[dbo].[Orders].[Orders_x01]))
--11 11
| |--Index Seek(OBJECT:([jwjung].[dbo].[Orders].[Orders_pk]
AS [c]), SEEK:([c].[OrderID]=[jwjung].[dbo].[Orders].[OrderID]) ORDERED
FORWARD)
--11 11
|--RID Lookup(OBJECT:([jwjung].[dbo].[Orders] AS [c]),
SEEK:([Bmk1004]=[Bmk1004]) LOOKUP ORDERED FORWARD)
--(11개 행이 영향을 받음)
--테이블 'Orders'. 검색 수 1, 논리적 읽기
수 73, 물리적 읽기 수 2, 미리 읽기 수 0, LOB 논리적 읽기 수 0, LOB 물리적 읽기 수 0, LOB 미리 읽기 수 0.
SET STATISTICS PROFILE OFF
SET STATISTICS TIME OFF
SET STATISTICS IO OFF