2008 년SQL 서버 성능 및 인덱싱 된 뷰는 SQL 서버를 사용
여러 개의 위치가 각각은 0에서부터 많은 스캔을 가질 수있는 여러 항목을 포함하는 여러 부서를 포함합니다. 각 스캔은 컷오프 시간을 갖거나 갖지 않을 수있는 특정 동작과 관련됩니다. 각 항목은 또한 특정 클라이언트에 속한 특정 프로젝트에 속하는 특정 작업에 속하는 특정 패키지에 속합니다. 각 작업에는 하나 이상의 항목이 들어있는 하나 이상의 패키지가 들어 있습니다.
항목 테이블에는 약 24,000,000 개의 레코드가 있고 스캔 테이블에는 대략 48,000,000 개의 레코드가 있습니다. 새 항목은 하루 동안 데이터베이스에 산발적으로 일괄 적으로 삽입됩니다. 일반적으로 수만 개에 달합니다. 새로운 스캔은 매시간, 수백에서 수십만에 이르는 대량으로 삽입됩니다.
이 테이블들은 어떤 식 으로든 쿼리, 슬라이싱 및 다이 싱됩니다. 나는 매우 구체적인 저장 procs을 쓰고 있었지만 사이트에서 끝이없는 백개의 procs에 직면했을 때 유지 관리의 악몽으로 변했다. (예를 들어, ScansGetDistinctCountByProjectIDByDepartmentIDGroupedByLocationID, ScansGetDistinctCountByPackageIDByDepartmentIDGroupedByLocationID 등과 같은 것). 거의 매일 변화하는 것 같은 느낌이 드는 변화. 칼럼을 변경/추가/삭제해야 할 때마다, 나는 바에서 끝난다.
그래서 필터링 된 그룹화를 결정하기 위해 매개 변수가있는 인덱스 된 뷰와 소수의 일반 저장된 procs를 만들었습니다. 불행히도, 성능은 화장실 아래로 갔다. 첫 번째 질문은 선택 성능이 가장 중요하기 때문에 특정 접근 방식을 고수하고 기본 테이블의 변경을 통해 싸워야한다는 것입니다. 또는 인덱싱 된 뷰/일반 쿼리 방식의 속도를 높이려면 무엇인가 할 수 있습니까? 유지 관리의 악몽을 없애기 위해 실제로 인덱스 된 뷰가 성능을 향상시킬 것으로 기대하고있었습니다.
CREATE VIEW [ItemScans] WITH SCHEMABINDING AS
SELECT
p.ClientID
, p.ID AS [ProjectID]
, j.ID AS [JobID]
, pkg.ID AS [PackageID]
, i.ID AS [ItemID]
, s.ID AS [ScanID]
, s.DateTime
, o.Code
, o.Cutoff
, d.ID AS [DepartmentID]
, d.LocationID
-- other columns
FROM
[Projects] AS p
INNER JOIN [Jobs] AS j
ON p.ID = j.ProjectID
INNER JOIN [Packages] AS pkg
ON j.ID = pkg.JobID
INNER JOIN [Items] AS i
ON pkg.ID = i.PackageID
INNER JOIN [Scans] AS s
ON i.ID = s.ItemID
INNER JOIN [Operations] AS o
ON s.OperationID = o.ID
INNER JOIN [Departments] AS d
ON i.DepartmentID = d.ID;
와 클러스터 된 인덱스 :
CREATE UNIQUE CLUSTERED INDEX [IDX_ItemScans] ON [ItemScans]
(
[PackageID] ASC,
[ItemID] ASC,
[ScanID] ASC
)
가 여기에 일반적인 저장 발동 중 하나 여기
뷰를 생성하는 코드입니다. 그것은 검사와 차단이 된 항목의 수를 가져옵니다CREATE NONCLUSTERED INDEX [IX_ItemScans_Counts] ON [ItemScans]
(
[Cutoff] ASC
)
INCLUDE ([ClientID],[ProjectID],[JobID],[ItemID],[SegmentID],[DepartmentID],[LocationID])
: 나는 쿼리를 실행하고 실제 실행 계획을보고 처음으로, 내가 제안하는 누락 된 인덱스를 생성
PROCEDURE [ItemsGetFinalizedCount]
@FilterBy int = NULL
, @ID int = NULL
, @FilterBy2 int = NULL
, @ID2 sql_variant = NULL
, @GroupBy int = NULL
WITH RECOMPILE
AS
BEGIN
SELECT
CASE @GroupBy
WHEN 1 THEN
CONVERT(sql_variant, LocationID)
WHEN 2 THEN
CONVERT(sql_variant, DepartmentID)
-- other cases
END AS [ID]
, COUNT(DISTINCT ItemID) AS [COUNT]
FROM
[ItemScans] WITH (NOEXPAND)
WHERE
(@ID IS NULL OR
@ID = CASE @FilterBy
WHEN 1 THEN
ClientID
WHEN 2 THEN
ProjectID
-- other cases
END)
AND (@ID2 IS NULL OR
@ID2 = CASE @FilterBy2
WHEN 1 THEN
CONVERT(sql_variant, ClientID)
WHEN 2 THEN
CONVERT(sql_variant, ProjectID)
-- other cases
END)
AND Cutoff IS NOT NULL
GROUP BY
CASE @GroupBy
WHEN 1 THEN
CONVERT(sql_variant, LocationID)
WHEN 2 THEN
CONVERT(sql_variant, DepartmentID)
-- other cases
END
END
인덱스를 만들면 실행 시간이 약 5 초가 걸렸지 만 이는 여전히 받아 들일 수없는 것입니다 (쿼리의 "특정"버전이 잠시 실행됩니다.) 인덱스에 다른 열을 추가하려고 시도했습니다. 성능 향상 (이 시점에서 내가 무엇을하고 있는지 전혀 알지 못한다.
그리고 여기가 컷오프가 NULL이 아닌 경우 뷰의 모든 행을 반환하는 표시 (추구 그 첫 번째 인덱스에 대한 세부 사항입니다) :) 여기
는 쿼리 계획이다
빠른 응답을 보내 주셔서 감사합니다. 나는 동적 SQL을 고려하지 않았다는 것을 인정해야한다. 나는 거기에 시간과 장소가 있다는 것을 알고 있지만, 여전히 "동적 인 SQL은 항상 악마 다"라고 내 머리 속에서 울리고 있습니다. 그것을 흔들 수없는 것. – Frank
'sp_executesql' 매개 변수는 procs의 많은 성능을 제공하며,'exec (@sql)'이라는 테러의 대부분을 피할 수 있습니다. 나는 반드시 "사용해야한다 ... PROCS!"의 시대를 생각한다. 불행히도 많은 데이터베이스에서 수 백개의 콜렉션을 유지하고 있지만, 대부분 우리 뒤에 있습니다. –
당신은 이것을 좋아할 것입니다 ... 만약 당신이 저의 저장된 proc을 보았다면, 파라미터를 선언 한 직후에 RECOMPILE을 가지고 있습니다. 그것을 제거하고 저장된 proc의 끝에 OPTION (RECOMPILE)을 추가하면, 그것은 날아간다. 나는 그 차이를 알만큼 충분히 똑똑하지 않습니다.하지만 링크를 게시하게되어 기쁩니다. Erland Sommarskog 사이트에서 저를 알아 차렸습니다. 사람들이 나에게 뭔가를하는 법 대신에 올바른 방향으로 나를 가리킬 때 나는 그것을 더 좋아하는 또 다른 이유. 다시 한번 감사드립니다. – Frank