현재 측량 응용 프로그램의 데이터 내보내기 기능을 사용하고 있습니다. 우리는 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;
동적 SQL은 질문 텍스트를 피벗의 열 이름으로 가져와야합니다. 병목 현상이 아닙니다. 적용 가능한 경우 sp_executesql 및 매개 변수를 사용하여 동적 SQL을 실행하므로 실행 계획이 다시 사용됩니다. 몇 가지 예제 SQL을 모의하려고합니다 ... –