我目前正在为调查应用程序开发数据导出功能。我们正在使用SQL2k8。我们以标准化格式存储数据:QuestionId,RespondentId,Answer。我们还有一些其他表格,用于定义QuestiondentId的QuestionId和受众特征的问题文本...
目前我正在使用一些动态SQL生成一个将问题表连接到答案表的枢轴并创建一个导出,它的工作......问题是它看起来很慢而且我们没有那么多的数据(不到5万的受访者)。
现在我在想“为什么我要付钱”来为每个查询分解数据?为什么我不缓存它?导出的数据基于动态标准。它可能是“给我在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 [为什么有空气?],XmlCol.RinseAndRepeat)。 ..
对此有更好的技术/方法吗?
谢谢!
编辑:用于测试的SQL Block。 运行步骤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;
答案 0 :(得分:0)
不,你的方法看起来不太好。保留标准化数据。如果你有正确的钥匙,解散的“成本”将是最小的。要进一步优化性能,请停止使用动态SQL。编写一些巧妙编写的查询并将它们封装在存储过程中。这将允许SQL服务器缓存查询计划,而不是每次都重建它们。
然而,在执行任何此操作之前,请检查查询计划。您可能忘记了至少一个要搜索的字段的索引,这将导致数据的全表扫描。您可以使用一些放置好的索引来大幅提高性能。