select value
from persons p join persons2 p2
on left(p.lastname,1) = left(p2.lastname,1)
SQL Server. 이 SARGable / 실행 속도를 높이는 방법이 있습니까? persons 테이블에는 열을 만들 수 없지만 persons2에는 열을 만들 수 있습니다.
select value
from persons p join persons2 p2
on left(p.lastname,1) = left(p2.lastname,1)
SQL Server. 이 SARGable / 실행 속도를 높이는 방법이 있습니까? persons 테이블에는 열을 만들 수 없지만 persons2에는 열을 만들 수 있습니다.
답변:
LEFT(lastname, 1)각 테이블에 대해 정의 된 지속 계산 열이있는 테이블에 대한보기 를 작성한 후 계산 지속 열 값을 비교하십시오.
다음은이를 수행하는 방법을 보여주는 테스트 베드입니다.
CREATE TABLE dbo.Persons
(
PersonID int NOT NULL
CONSTRAINT PK_Persons
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, FirstName nvarchar(500) NOT NULL
, LastName nvarchar(500) NOT NULL
);
CREATE TABLE dbo.Persons2
(
PersonID int NOT NULL
CONSTRAINT PK_Persons2
PRIMARY KEY CLUSTERED
IDENTITY(1,1)
, FirstName nvarchar(500) NOT NULL
, LastName nvarchar(500) NOT NULL
);
GO
CREATE VIEW dbo.PersonsView
WITH SCHEMABINDING
AS
SELECT p1.PersonID
, p1.FirstName
, p1.LastName
, LastNameInitial = LEFT(p1.LastName, 1)
FROM dbo.Persons p1;
GO
CREATE VIEW dbo.PersonsView2
WITH SCHEMABINDING
AS
SELECT p2.PersonID
, p2.FirstName
, p2.LastName
, LastNameInitial = LEFT(p2.LastName, 1)
FROM dbo.Persons p2;
GO
CREATE UNIQUE CLUSTERED INDEX CX_PersonsView
ON dbo.PersonsView(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView_LastNameInitial
ON dbo.PersonsView(LastNameInitial)
INCLUDE (FirstName, LastName);
CREATE UNIQUE CLUSTERED INDEX CX_PersonsView2
ON dbo.PersonsView2(PersonID);
CREATE NONCLUSTERED INDEX IX_PersonsView2_LastNameInitial
ON dbo.PersonsView2(LastNameInitial)
INCLUDE (FirstName, LastName);
CREATE STATISTICS ST_PersonsView_001
ON dbo.PersonsView(LastName);
CREATE STATISTICS ST_PersonsView2_001
ON dbo.PersonsView2(LastName);
다음은 몇 가지 샘플 데이터를 삽입합니다.
INSERT INTO dbo.Persons(FirstName, LastName)
VALUES ('Max', 'Vernon')
, ('Joe', 'Black');
INSERT INTO dbo.Persons2(FirstName, LastName)
VALUES ('Max', 'Vernon')
, ('Joe', 'Black');
SELECT쿼리 는 다음과 같습니다 .
SELECT *
FROM dbo.PersonsView pv1
INNER JOIN dbo.PersonsView2 pv2 ON pv1.LastNameInitial = pv2.LastNameInitial;
그리고 결과 :
+ ---------- + ----------- + ------------ + ----------------- -+ ---------- + ----------- + ------------ + --------------- ---- + | PersonID | 이름 | 성 | 성 이니셜 | PersonID | 이름 | 성 | 성 이니셜 | + ---------- + ----------- + ------------ + ----------------- -+ ---------- + ----------- + ------------ + --------------- ---- + | 2 | 조 | 블랙 | B | 2 | 조 | 블랙 | B | | 1 | 최대 | 버논 | V | 1 | 최대 | 버논 | V | + ---------- + ----------- + ------------ + ----------------- -+ ---------- + ----------- + ------------ + --------------- ---- +
테이블 당 2 개의 행만있는 실행 계획 (행이 많지 않음)
lastname열이 하나 이상의 테이블에서 색인화 되면 다음을 사용할 수도 있습니다.LIKE
SELECT *
FROM persons p
INNER JOIN persons2 p2
ON p2.lastname LIKE LEFT(p.lastname, 1) + '%'
이에 대한 계획은 왼쪽에 지정된 테이블을 탐색 할 수 있습니다.
즉 위에 사용 된 ON p.lastname LIKE LEFT(p2.lastname, 1) + '%'인덱스를 사용할 수는 없지만 인덱스를 persons2사용할 수 있습니다 persons.
그러나 양쪽에서 계산 열을 인덱싱한다는 다른 대답은 더 유연합니다. 중첩 루프 계획의 경우 두 테이블 중 하나가 내부에있을 수 있으며 정렬없이 많은 수의 병합 조인을 허용 할 수도 있습니다.
에 3,423 개의 행과 195 개의 고유 값이있는 테이블이 Name있습니다. 이 테이블 P(person)을 호출 하고 생성하여 P2(person2) 복제합니다 . 정수 ID 열에는 고유 한 클러스터 된 기본 키가 있습니다. 32GB RAM이있는 Windows 10 Pro 6.3에서 Microsoft SQL Server 2016 (KB3194716) Developer Edition (64 비트)을 사용하고 있습니다.
기본 검색어
select
p.pid
from dbo.p
inner join dbo.p2
on LEFT(p.name, 1) = LEFT(p2.name, 1);
3200-3300ms에 1.5M 개의 행이 반환됩니다 (통계 io에서).
이렇게 다시 쓰면-
select
p.pid
from dbo.p
where exists
(
select 1
from dbo.p2
where LEFT(p.name, 1) = LEFT(p2.name, 1)
);
경과 시간은 50-60ms로 줄어들고 계획은 다음과 같습니다.
일치 알고리즘으로 인해 더 적은 행이 반환됩니다 (3,423). 기본 쿼리를로 변경하여 동일한 계획 및 행 수를 얻을 수 select distinct있습니다.
인덱스 된 계산 열을 생성하여
alter table dbo.p2
add Name1 as Left(Name, 1);
create index ix1 on dbo.p2(Name1);
경과 시간은 45-50ms로 떨어집니다.