안녕 42,400 행을 보유하는 테이블이 있습니다. 이것은 SQL 표준에 비해 매우 작습니다.작은 자체 조인 쿼리
테이블은 시설의 위치를 유지하며 부모/자식 관계로 설계되었습니다.
CREATE TABLE [dbo].[Location](
[Id] [int] IDENTITY(1,1) NOT NULL,
[ParentLocationId] [int] NULL,
[Description] [varchar](100) NOT NULL,
[LocationTypeId] [int] NOT NULL,
[IsDeleted] [bit] NOT NULL,
CONSTRAINT [pk_Location] 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]
은 5 개 행을 가지고 locationType에 테이블에 외부 키가 있습니다.
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [fk_location_locationtype] FOREIGN KEY([LocationTypeId])
REFERENCES [ref].[LocationType] ([Id])
GO
또한 자기 자신을 가지고 있습니다.
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [fk_LocationLocation] FOREIGN KEY([ParentLocationId])
REFERENCES [dbo].[Location] ([Id])
GO
부모에게는 많은 자녀가있을 수 있습니다. 그러나 고정 된 수의 위치 수준이 있습니다. 위치 정보를 많이 묻습니다.
그래서 위치 데이터를 가져 오기위한보기를 구현했습니다.
조금 깁니다.하지만 바닥에 있습니다. 그러나 귀가 줄을 채우고 그 다음에 아이들과 결합하여 결과 집합을 반환하는 것이 좋습니다. 예를 들어
:
선택 곳에 위치 레벨 = 1 (루트) 다음 위치 레벨 2, 그리고 그것의 부모에 가입을 선택합니다. 다음 위치 수준 3을 선택하고 부모와 그 부모와 합류합니다.
현재 성능 문제가있는 것 같습니다. 먼저 아이의와 나는 위치에 따라 행 인을 찾고 결과를 달성하기 위해 더 나은 방법 ...
첫 번째 행은 루트 노드입니다 ... 2 루트가 존재입니다
SELECT
l1.Id as LocationId,
l1.LocationTypeId,
lt.DisplayName,
l1.ParentLocationId,
l1.Description AS thisLocationName,
l1.IsDeleted,
l1.Description AS Level1,
NULL AS Level2,
NULL AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN ref.LocationType lt
ON lt.Id = l1.LocationTypeId
AND lt.level = 1
UNION
SELECT
l2.Id AS LocationId,
l2.LocationTypeId,
lt.DisplayName,
l2.ParentLocationId,
l2.Description AS thisLocationName,
l1.IsDeleted | l2.IsDeleted,
l1.Description AS Level1,
l2.Description AS Level2,
NULL AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN [dbo].Location l2
ON l2.ParentLocationId = l1.Id
INNER JOIN ref.LocationType lt
ON lt.Id = l2.LocationTypeId
AND lt.level = 2
UNION
SELECT
l3.Id AS LocationId,
l3.LocationTypeId,
lt.DisplayName,
l3.ParentLocationId,
l3.Description AS thisLocationName,
l1.IsDeleted | l2.IsDeleted | l2.IsDeleted,
l1.Description AS Level1,
l2.Description AS Level2,
l3.Description AS Level3,
NULL AS Level4,
NULL AS Level5,
NULL AS Level6,
NULL AS Level7,
NULL AS Level8,
NULL AS Level9,
NULL AS Level10
FROM [dbo].Location l1
INNER JOIN [dbo].Location l2
ON l2.ParentLocationId = l1.Id
INNER JOIN [dbo].Location l3
ON l3.ParentLocationId = l2.Id
INNER JOIN ref.LocationType lt
ON lt.Id = l3.LocationTypeId
AND lt.level = 3
UNION
.... (This occurs for 10 levels)
여기 테이블에 대한 그래서 데모 데이터입니다 :
.. 그것으로 뿌리가 두번째 아이의 특정 위치에 선택을하는 예이다.
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(1, NULL, 'A Building', 1)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(2, 1, '1st Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(3, 1, '2nd Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(4, 1, '3rd Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(5, 1, '4th Floor', 2)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(6, 1, 'Boardroom', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(7, 1, 'Main Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(8, 1, 'Directors Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(9, 1, 'Kitchen', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(10, 2, 'Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(11, 2, 'Meeting Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(12, 2, 'Kitchen', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(13, 2, 'Gents WC', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(14, 2, 'Ladies WC', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(15, 3, 'Office 1', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(16, 3, 'Office 2', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(17, 3, 'Office 3', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(18, 3, 'Office 4', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(19, 3, 'Meeting Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(20, 3, 'Staff Room', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(21, 4, 'Small Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(22, 4, 'Medium', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(23, 4, 'Large Office', 3)
INSERT INTO Location
(Id, ParentLocationId, Description, LocationTypeId)
VALUES
(24, 4, 'Meeting Room', 3)
나는 시도 한 CTE 버전은 아래의 추천 :
CREATE VIEW [dbo].[vwLocations3]
WITH SchemaBinding
AS
with h as (
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, convert(varchar(100), null) level2
, convert(varchar(100), null) level3
, convert(varchar(100), null) level4
, convert(varchar(100), null) level5
, convert(varchar(100), null) level6
, convert(varchar(100), null) level7
, convert(varchar(100), null) level8
, convert(varchar(100), null) level9
from dbo.Location l
where ParentLocationId IS NULL
UNION ALL
select l.Id, l.ParentLocationId, l.Description, l.LocationTypeId, l.IsDeleted
, case when l.LocationTypeId = 2 then l.Description when l.LocationTypeId > 2 then h.Description end level2
, case when l.LocationTypeId = 3 then l.Description when l.LocationTypeId > 3 then h.Description end level3
, case when l.LocationTypeId = 4 then l.Description when l.LocationTypeId > 4 then h.Description end level4
, case when l.LocationTypeId = 5 then l.Description when l.LocationTypeId > 5 then h.Description end level5
, case when l.LocationTypeId = 6 then l.Description when l.LocationTypeId > 6 then h.Description end level6
, case when l.LocationTypeId = 7 then l.Description when l.LocationTypeId > 7 then h.Description end level7
, case when l.LocationTypeId = 8 then l.Description when l.LocationTypeId > 8 then h.Description end level8
, case when l.LocationTypeId = 9 then l.Description when l.LocationTypeId > 9 then h.Description end level9
from h
inner join dbo.Location l on l.ParentLocationId = h.id
)
SELECT
h.Id AS LocationId,
h.LocationTypeId,
lt.DisplayName,
h.ParentLocationId,
h.Description AS thisLocationName,
--h.Level1,
h.Level2,
h.Level3,
h.Level4,
h.Level5,
h.Level6,
h.Level7,
h.Level8,
h.Level9
--cte.Level10
FROM h
INNER JOIN ref.LocationType lt
ON lt.Id = h.LocationTypeId
하지만이 1,500ms의 선택을 반환합니다.
UNION은 UNION ALL –
감사 @Used_By_Already보다 느린, 중복을 제거합니다. – Craig
질문에 샘플 데이터를 추가하십시오 (모든 10 레벨은 필요하지 않고 몇 줄만 사용). 이미지를 사용하지 마십시오. 또한 해당 데이터 샘플에서 예상되는 결과를 추가하십시오. –