【发布时间】:2010-04-26 00:01:26
【问题描述】:
我目前正在为调查应用程序开发数据导出功能。我们正在使用 SQL2k8。我们以标准化格式存储数据:QuestionId、RespondentId、Answer。我们还有几个其他表格,它们定义了 QuestionId 的问题文本和 RespondentId 的人口统计...
目前我正在使用一些动态 SQL 来生成一个将问题表连接到答案表并创建导出的数据透视表,它正在工作......问题是它看起来很慢而且我们没有那么多数据(少于 50,000 名受访者)。
现在我在想“为什么我要‘付费’去聚合每个查询的数据?我为什么不缓存它?”导出的数据基于动态标准。可能是“给我在 x 日期(或范围)完成的受访者”或“喜欢蓝色的人”等。因此,我认为我必须在受访者级别缓存,找出正在导出的受访者和然后选择他们组合的缓存去聚合数据。
对我来说,快速而肮脏的解决方案是一个完全扁平的表、RespondentId、Question1、Question2 等。问题是,我们有多个客户端并且无法扩展,我不想维护扁平化的表表随着调查的变化而变化。
所以我正在考虑在响应者表上放置一个 XML 列并缓存 SELECT * FROM Data FOR XML AUTO WHERE RespondentId = x 的结果。有了这些,我就可以通过过滤和 XML 调用将我的导出导出到 XML 列中。
您如何以扁平格式(CSV、Excel 等)导出汇总数据?这种方法看起来可以吗?我担心 XML 函数在较大结果集上的成本(想想 SELECT RespondentId, XmlCol.value('//data/question_1', 'nvarchar(50)') AS [Why is there air?], XmlCol.RinseAndRepeat)。 ..
有更好的技术/方法吗?
谢谢!
编辑:用于测试的 SQL 块。 运行第 1 步和第 2 步以准备数据,使用第 3 步进行测试,使用第 4 步进行清理... 一千个受访者乘一百个问题,这似乎已经比我想要的要慢了。
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-server xml caching export