1

테이블 "empl"의 65 개 열 모두가 페이징에 최소 IO로로드되도록 요구 사항이로드됩니다. 테이블에는 280000+ 개의 레코드가 있습니다. PK를 통해 클러스터 된 인덱스는 하나뿐입니다. CPU인덱스를 넣은 후 읽기가 낮아지지 않습니다.

: 1500 읽습니다 : 25576, 소요 시간 :

매김 쿼리는 다음과 같습니다 : 프로파일에서 위의 쿼리를 실행 한 후 통계

WITH result_set AS ( 
SELECT  
ROW_NUMBER() OVER (ORDER BY e.[uon] DESC) AS [row_number], e.*  
FROM  
empl e with (NOLOCK)  
LEFT JOIN empl_add ea with (NOLOCK)  
ON ea.ptid = e.ptid  
WHERE  
e.del = 0 AND e.pub = 1 AND e.sid = 2 
AND e.md = 0  
AND e.tid = 3  
AND e.coid = 2  
AND (e.cid = 102) 
AND ea.ptgid IN (SELECT ptgid FROM empl_dep where psid = 1001 
AND ib = 1)) 
SELECT 
* 
FROM 
result_set 
WHERE 
[row_number] BETWEEN 0 AND 50 

다음은 그런 25,704

내가 테이블 empl에 다음 색인을 붙여 넣으십시오.

어미스트 퍼팅 인덱스 CPU와 읽기가 여전히 높습니다. 인덱스에 어떤 문제가 있는지 또는 쿼리에 문제가 있는지 알 수 없습니다.

편집 :

는 다음 쿼리는 또한 높은 복용은 인덱스를 붙여서 읽습니다. 그리고 3 개의 열과 1 개의 카운트 만 있습니다.

SELECT TOP (2147483647) 
ame.aid ID, ame.name name,   
COUNT(empl.pid) [Count], ps.uff uff FROM ame with (NOLOCK)   
JOIN pam AS pa WITH (NOLOCK) ON pa.aid = ame.aid   
JOIN empl WITH (NOLOCK) ON empl.pid = pa.pid   
LEFT JOIN psam AS ps 
ON ps.psid = 1001 
AND ps.aid = ame.aid 
LEFT JOIN empl_add ea with (NOLOCK)   
ON ea.ptid = empl.ptid   
WHERE 
empl.del = 0 AND empl.pub = 1 AND empl.sid = 2 
AND empl.md = 0   
AND (empl.tid = 3)   
AND (empl.coid = 2)   
AND (empl.cid = 102)   
AND ea.ptgid IN (SELECT ptgid FROM empl_dep where psid = 1001 
AND ib = 1)   
AND ame.pub = 1 AND ame.del = 0   
GROUP BY ame.aid, ame.name, ps.uff   
ORDER BY ame.name ASC 

두 번째 편집 :

지금은 "UON"열에서 다음 인덱스를 넣어했다 :

CREATE NONCLUSTERED INDEX [ci_empl_uon] 
ON [dbo].[empl] (uon) 
GO 

하지만 여전히 CPU와 높은 읽습니다.

세 번째 편집 :

모든 열이 첫 번째 쿼리에 포함와 내가 제안 된 인덱스를 만들기 위해 기본 4 개 개의 필터에 대한 필터 인덱스로 변환 변경 DTA 나에게 인덱스를 제안한다

것이 더 효과적 .

다음 줄을 추가하여 색인을 만드는 동안을 포함시킵니다.

그러나 개발 및 프로덕션 컴퓨터에서 여전히 읽기가 높습니다.

넷째 편집 :

은 지금은하지 최대 목표로 여전히 성능을 개선하는 솔루션에 와서 만했다. 열쇠는 그것이 가려고하지 않는다는 것입니다. 모든 데이터.

WITH result_set AS ( 
SELECT  
ROW_NUMBER() OVER (ORDER BY e.[uon] DESC) AS [row_number], e.pID pID 
FROM  
empl e with (NOLOCK)  
LEFT JOIN empl_add ea with (NOLOCK)  
ON ea.ptid = e.ptid  
WHERE  
e.del = 0 AND e.pub = 1 AND e.sid = 2 
AND e.md = 0  
AND e.tid = 3  
AND e.coid = 2  
AND (e.cid = 102) 
AND ea.ptgid IN (SELECT ptgid FROM empl_dep where psid = 1001 
AND ib = 1)) 
SELECT 
* 
FROM 
result_set join empl on result_set.pID = empl.pID 
WHERE 
[row_number] BETWEEN @start AND @end 

을 그리고 키 열 변경으로 인덱스를 다시 포함 및 필터 :

CREATE NONCLUSTERED INDEX [ci_empl] 
ON [dbo].[empl] ([ptid],[cid],[tid],[uon]) 
INCLUDE ([pID]) 
Where 
[coID] = 2 and 
[sID] = 2 and 
[pub] = 1 and 
[del] = 0 and 
[md] = 0 
GO 

그것은 성능을 향상 아니라 목표까지

쿼리는이 다음이다.

+0

'SELECT *'를 사용하여 테이블에서 ** 모든 ** 열을 선택한다. - SQL 엔진이 비 클러스터형 인덱스의 데이터 페이지 (클러스터 된 인덱스)로 되돌아 가야 ** 모든 ** 열을 가져올 수 있기 때문에 인덱스가 도움이되지 않을 수 있습니다. 종종 쿼리 최적화 프로그램이 ** (클러스터 된) 인덱스 스캔 **을 사용하게합니다 ** –

+0

열이 읽기 수를 줄입니까? 인덱스가 테이블보다 적은 데이터를 저장한다고 생각하십니까? 왜 그랬을까요? * 모든 * 데이터의 복사본이 포함되어 있습니다! 내 음악 라이브러리를 두 번째 컴퓨터에 복사하면 디스크 공간을 덜 차지해야합니까? –

+0

@Aaron : 색인은 키 열에 만 사용되며 모든 열에는 사용되지 않습니다. – Prakash

답변

0

e.uon desc으로 정렬 된 상위 50 개의 행을 선택합니다. 인덱스는 SQL Server가이 지수의 상위 N 행을 검색 할 수

create index IX_Empl_Uon on dbo.empl (uon) 

: uon 시작 인덱스는 쿼리 속도가 향상됩니다. N은 페이지 매김에서 가장 높은 숫자입니다. 50 번째 요소의 세 번째 페이지에서 N은 150과 같습니다. SQL Server는 50 개의 키 조회를 수행하여 클러스터 된 인덱스에서 전체 행을 검색합니다. 제가 아는 한, 이것은 색인이 큰 차이를 만들 수있는 교과서의 예입니다.

모든 쿼리 최적화 프로그램이 row_number() over ... as rnwhere rn between 1 and 50이 상위 50 개 행을 의미하는 것을 알 수있을만큼 똑똑하지는 않습니다. 그러나 SQL Server 2012는 않습니다. row_number() between 50 and 99과 같이 첫 번째 페이지와 연속 된 페이지 모두에 대해 색인을 사용합니다.

+0

해당 인덱스에서 50 개의 행을 찾기 위해 범위 스캔 (검색으로 가장함)을 수행하는 경우 나머지 열을 얻으려면 50 개의 조회를 수행해야하므로 세척 정도가 다를 수 있습니다 "확실히 알기 위해). –

+0

@AaronBertrand : 50 개의 조회가 300K 행 스캔을 이겨야합니다. 나에게 그것은 인덱스가 유용 할 곳의 교과서 예제와 같이 보인다. – Andomar

+0

@Andomar 요구 사항은 상위 50 개 행뿐 아니라 페이지 매김입니다. – Prakash

0

u-column으로 지정된 순서에 따라 데이터 세트에서 X부터 X + N 번째 행까지를 찾으려고합니다.

여기서는 uon이 언급 된 기본 키라고 가정합니다. 그렇지 않은 경우, uon이 첫 x 째 컬럼이 아닌 인덱스가 없으면 테이블 스캔이 불가피합니다.

다음 주름 : 열의 직접적인 범위를 원하지 않으면 열의 범위를 으로 상당히 다양한 필터로 필터링해야합니다. 클러스터 된 인덱스는 처음 50 개의 열을 가져올 수 있지만 WHERE는 필터링하지 않을 수도 있고 일부만 필터링 할 수도 있습니다. 더 많은 것은 거의 확실하게 "귀하의 기간을 채우기"위해 읽어야합니다.

재미있는 점 : empl_add 테이블에서 왼쪽 외부 조인을 수행 한 경우 (예 : empl_add가없는 경우에도 empl 행을 retaing) empladd.ptgid가 하위 쿼리에서 발견되지 않는 모든 행을 필터링해야합니다. 이걸 내부 결합으로 만들 수도 있고, 일을 더 빠르게 할 수도 있고 확실히 느리게 만들 수도 없습니다. 테이블 empl에 대한 색인으로 처리 할 수없는 "필터링 요소"이기도합니다.

그래서 내가 본 것처럼 (즉, 로컬에서 모든 것을 테스트하지는 않는다), SQL은 먼저 데이터를 어셈블하고, 잘못된 조인 (테이블 조인과 관련된)을 필터링하고, 남아있는 것을 정렬 한 다음이를 반환해야한다 관심있는 행의 범위. 나는 uon에 대한 색인이 있건 없건간에 SQL이 원하는 범위를 고를 수 있기 전에 모든 데이터와 필터/정렬을 읽을 필요가 있는지 확인하고 있습니다.

(새 색인은 충분하지 않습니다 .6 번째 열은 sid이지만 sid는 쿼리에서 참조되지 않으므로 "지금까지"도움이 될 수 있습니다. 이로 인해 데이터 카디널리티에 대해 많은 질문이 제기됩니다. 우리는 전체 분석을 위해 설정 한 전체 문제에 대한 정보가 충분하지 않다는 사실을 @Aarons의 주장에 맡긴다.)

+0

"uon"은 DateTime 열, "pid"는 기본 키 – Prakash

+0

"stid"는 "sid"였습니다. 동일한 수정했습니다 – Prakash

+0

주문한대로 처음 50 개 행을 원한다면 열 uon에 대한 인덱스가없고 uon 열에 인덱스가없는 경우 SQL은 "첫 번째"50을 찾으려면 테이블의 모든 행을 읽어야합니다. –

관련 문제