Je travaille actuellement sur une fonctionnalité d'exportation de données pour une application d'enquête. Nous utilisons SQL2k8. Nous stockons les données dans un format normalisé: QuestionId, RespondentId, Answer. Nous avons quelques autres tables qui définissent le texte de la question pour le QuestionId et les données démographiques pour le RespondentId ...Exportation de données désagrégées
Actuellement, j'utilise du SQL dynamique pour générer un pivot qui joint la table de questions à la table de réponses et crée une exportation, son fonctionnement ... Le problème est qu'il semble lent et nous n'avons pas beaucoup de données (moins de 50k répondants).
À l'heure actuelle, je me demande «pourquoi est-ce que je« paie »pour désagréger les données de chaque requête, pourquoi ne les cache-t-on pas? Les données exportées sont basées sur des critères dynamiques. Cela pourrait être «donnez-moi les répondants qui ont terminé x date (ou intervalle)» ou «les gens qui aiment bleu», etc. Pour cette raison, je pense que je dois mettre en cache au niveau des répondants, savoir ce que les répondants sont exportés et sélectionnez ensuite leurs données combinées désagrégées en mémoire cache.
Pour moi, le correctif rapide et incorrect est une table totalement plate, RespondentId, Question1, Question2, etc. Le problème est, nous avons plusieurs clients et cela ne change pas ET je ne veux pas avoir à maintenir le table aplatie à mesure que l'enquête change. Je pense donc à mettre une colonne XML sur la table des répondants et à mettre en cache les résultats d'un SELECT * FROM Données pour XML AUTO WHERE RespondentId = x. Avec cela en place, je serais alors en mesure d'obtenir mon exportation avec filtrage et appels XML dans la colonne XML.
Que faites-vous pour exporter des données agrégées dans un format aplati (CSV, Excel, etc.)? Cette approche semble-t-elle correcte? Je m'inquiète du coût des fonctions XML sur des ensembles de résultats plus importants (pensez à SELECT RespondentId, XmlCol.value ('// data/question_1', 'nvarchar (50)') AS [Pourquoi y a-t-il de l'air?], XmlCol.RinseAndRepeat).
Y a-t-il une meilleure technologie/approche pour cela?
Merci!
EDIT: Bloc SQL pour test. Exécuter les étapes 1 & 2 pour initialiser les données, tester avec l'étape 3, nettoyer à l'étape 4 ... À un millier de répondants par cent questions, il semble déjà plus lent que je le voudrais.
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;
Le SQL dynamique est requis pour obtenir le texte de la question en tant que noms de colonne pour le pivot. Ce n'est pas un goulot d'étranglement. J'exécute le SQL dynamique en utilisant sp_executesql et les paramètres le cas échéant, de sorte que le plan d'exécution est en cours de réutilisation. Je vais essayer de simuler un exemple de SQL ... –