2010-04-26 6 views
0

현재 측량 응용 프로그램의 데이터 내보내기 기능을 사용하고 있습니다. 우리는 SQL2k8을 사용하고 있습니다. QuestionId, RespondentId, Answer 정규화 된 형식으로 데이터를 저장합니다. 우리는 질문 텍스트가 RespondentID에 대한 QuestionId 및 인구 통계에 대한 정의를하는 몇 가지 테이블을 가지고 있습니다 ...집계 해제 된 데이터 내보내기

현재 일부 동적 SQL을 사용하여 질문 테이블을 응답 테이블에 조인하고 문제는 그것이 느린 것 같고 우리는 많은 데이터 (50k 미만의 응답자)가 없다는 것입니다.

지금 당장 나는 "각 쿼리의 데이터를 집계하는 데 '돈을 지불하고 있습니까? 왜 캐시하지 않을까요?'라고 생각하고 있습니다. 내보낼 데이터는 동적 기준을 기반으로합니다. "x 날짜 (또는 범위)에서 완료된 응답자"또는 "파란색을 좋아하는 사람들"등이 될 수 있습니다. 그 때문에 응답자 수준에서 캐시하고 응답자를 내보내고 결합 된 캐쉬 해제 된 집계 데이터를 선택하십시오.

나에게 빠르고 더러운 수정은 완전히 평평한 테이블, RespondentId, Question1, Question2 등입니다. 문제는 우리가 여러 클라이언트를 보유하고 있으며 규모가 조정되지 않고 유지 관리를 원하지 않는다는 것입니다. 설문 조사가 변경되면서 평평한 테이블.

그래서 응답 테이블에 XML 열을 넣고 SELECT * FROM 데이터의 XML 캐싱에 대한 정보를 RespondentId = x로 캐싱하려고합니다. 그런 다음 필자는 필터링 및 XML 호출을 통해 내 내보내기를 XML 열로 가져올 수 있습니다.

집계 된 데이터를 병합 된 형식 (CSV, Excel 등)으로 내보내려면 어떻게해야합니까? 이 방법이 괜찮은 것 같습니까? 더 큰 결과 집합에 대한 XML 함수의 비용에 대해 걱정합니다 (SELECT RespondentId, XmlCol.value ('// data/question_1', 'nvarchar (50)') AS [왜 그렇습니까?], XmlCol.RinseAndRepeat). ..

더 나은 기술/접근 방법이 있습니까?

감사합니다.

EDIT : 테스트를위한 SQL 블록. 단계 1 & 2를 실행하여 데이터를 프라임하고 3 단계로 테스트 한 후 4 단계로 정리하십시오. 100 명이 넘는 응답자는 이미 저보다 느립니다.

SET NOCOUNT ON; 

-- step 1 - create seed data 
CREATE TABLE #Questions (QuestionId INT PRIMARY KEY IDENTITY (1,1), QuestionText VARCHAR(50)); 
CREATE TABLE #Respondents (RespondentId INT PRIMARY KEY IDENTITY (1,1), Name VARCHAR(50)); 
CREATE TABLE #Data (QuestionId INT NOT NULL, RespondentId INT NOT NULL, Answer INT); 

DECLARE @QuestionTarget INT = 100 
    ,@QuestionCount INT = 0 
    ,@RespondentTarget INT = 1000 
    ,@RespondentCount INT = 0 
    ,@RespondentId INT; 

WHILE @QuestionCount < @QuestionTarget BEGIN 
    INSERT INTO #Questions(QuestionText) VALUES(CAST(NEWID() AS CHAR(36))); 
    SET @QuestionCount = @QuestionCount + 1; 
END; 

WHILE @RespondentCount < @RespondentTarget BEGIN 
    INSERT INTO #Respondents(Name) VALUES(CAST(NEWID() AS CHAR(36))); 
    SET @RespondentId = SCOPE_IDENTITY(); 
    SET @QuestionCount = 1; 

    WHILE @QuestionCount <= @QuestionTarget BEGIN 
     INSERT INTO #Data(QuestionId, RespondentId, Answer) 
      VALUES(@QuestionCount, @RespondentId, ROUND(((10 - 1 -1) * RAND() + 1), 0)); 

     SET @QuestionCount = @QuestionCount + 1; 
    END; 

    SET @RespondentCount = @RespondentCount + 1; 
END; 

-- step 2 - index seed data 
ALTER TABLE #Data ADD CONSTRAINT [PK_Data] PRIMARY KEY CLUSTERED (QuestionId ASC, RespondentId ASC); 
CREATE INDEX DataRespondentQuestion ON #Data (RespondentId ASC, QuestionId ASC); 

-- step 3 - query data 
DECLARE @Columns NVARCHAR(MAX) 
    ,@TemplateSQL NVARCHAR(MAX) 
    ,@RunSQL NVARCHAR(MAX); 

SELECT @Columns = STUFF(
    (
     SELECT DISTINCT '],[' + q.QuestionText 
     FROM #Questions AS q 
     ORDER BY '],[' + q.QuestionText 
     FOR XML PATH('') 
    ), 1, 2, '') + ']'; 

SET @TemplateSql = 
'SELECT * 
FROM 
(
    SELECT r.Name, q.QuestionText, d.Answer 
    FROM #Respondents AS r 
     INNER JOIN #Data AS d ON d.RespondentId = r.RespondentId 
     INNER JOIN #Questions AS q ON q.QuestionId = d.QuestionId 
) AS d 
PIVOT 
(
    MAX(d.Answer) 
    FOR d.QuestionText 
    IN (xxCOLUMNSxx) 
) AS p;'; 

SET @RunSql = REPLACE(@TemplateSql, 'xxCOLUMNSxx', @Columns) 
EXECUTE sys.sp_executesql @RunSql; 

-- step 4 - clean up 
DROP INDEX DataRespondentQuestion ON #Data; 
DROP TABLE #Data; 
DROP TABLE #Questions; 
DROP TABLE #Respondents; 

답변

0

아니요, 접근 방식이 좋지 않은 것 같습니다. 정규화 된 데이터를 유지하십시오. 적절한 키를 가지고있는 경우, "비용"을 최소화 할 수 있습니다. 성능을 더욱 최적화하려면 동적 SQL을 사용하지 마십시오. 독창적으로 작성된 쿼리를 작성하고 저장 프로 시저에 캡슐화하십시오. 이렇게하면 SQL Server는 매번 쿼리 계획을 다시 작성하지 않고 캐시 할 수 있습니다.

그러나이 작업을 수행하기 전에 쿼리 계획을 확인하십시오. 또한 검색중인 필드 중 하나 이상에서 색인을 잊어 버릴 수 있으므로 전체 표 스캔 데이터가 생성됩니다. 잘 배치 된 인덱스를 사용하여 성능을 크게 향상시킬 수 있습니다.

+0

동적 SQL은 질문 텍스트를 피벗의 열 이름으로 가져와야합니다. 병목 현상이 아닙니다. 적용 가능한 경우 sp_executesql 및 매개 변수를 사용하여 동적 SQL을 실행하므로 실행 계획이 다시 사용됩니다. 몇 가지 예제 SQL을 모의하려고합니다 ... –