web-dev-qa-db-fra.com

Indice de colonne pour la table de paires de clé / valeur sur SQL Server

J'ai besoin de créer une base de données pour stocker des évaluations.

Chaque évaluation peut avoir un nombre indéfini de questions et un nombre indéfini de réponses.

Les réponses pour chaque évaluation peuvent atteindre 500 000.

Les questions pour chaque évaluation peuvent être de 10 à 200.

Bien que les tables d'évaluation et d'évaluationResponses soient conçues avec la table relationnelle "normale", les questions et les réponses doivent être stockées comme une paire de clé/valeur.

Assessments
|AssessmentID|Name|JsonSchema|

Questions
|QuestionID|AssessmentID|QuestionValue|QuestionType|

AssessmentResponses
|ResponseID|AssessmentID|RespondentName|Date|JsonResponse|

Answers
|ResponseID|QuestionID|AnswerValueText|AnswerValueDecimal|

Comme vous pouvez le constater, je stocke également le schéma d'évaluation et les réponses au format JSON, car j'ai trouvé utile de visualiser rapidement sur une interface utilisateur Web. JsonResponse, en particulier, contient tous les réponses donné dans le réponse, comme ce qui suit:

{
  "interviewDate":"2001/12/28",
  "city":"Mombasa",
  "phone":"123456789",
  "name":"Marco",
  "age":16
}

Les requêtes typiques peuvent être:

  1. Extraire toutes les réponses (pagies) d'un ASSENSEMENTSEMENT.
  2. Calculez la moyenne sur tous les réponses d'un fichier particulier évaluation de la touche âge.
  3. Extraire toutes les réponses où la clé "Âge" a une valeur supérieure à 25 et la clé "Ville" est égale à "New York"

Veuillez noter que pour la requête NO.2, les valeurs d'âge seront stockées dans la colonne réponde répandue, où je stocke toutes les valeurs numériques.

Je me demande si le index de colonne augmentera le Performance dans cette structure?

Veuillez noter que je sais qu'un exemple d'élasticsearch vous aidera beaucoup mais pour un problème de budget que nous ne pouvons pas mettre en œuvre à ce stade.

Quelques détails sur les données

Les réponses aux questions des évaluations sont généralement choisies parmi un nombre limité de choix. Par exemple:

  • Es-tu marié? > [Oui, non]
  • Type de bâtiment? > [Béton, squelette, draps éternites, feuilles de fer, autre]
  • Zone de la ville? > [Nord, Sud, Est, Ouest, Centre]

Les requêtes peuvent être construites par l'utilisateur final en fonction des informations dont ils ont besoin d'une évaluation particulière. Donner l'exemple ci-dessus, ils veulent savoir combien de bâtiments éternités se trouvent dans la région nord et ouest de la ville, compte à la fin.

Mais par exemple, il y a aussi une question "quel âge avez-vous?", Ils veulent filtrer la requête précédente pour savoir combien de bâtiments éternités se trouvent dans la région nord et ouest où il y a une personne âgée de moins de 25 ans ...

tilisation de champ JSON pour stocker des données

J'ai essayé d'utiliser la nouvelle fonctionnalité de SQL Server 2016/2017 pour stocker le document JSON à l'intérieur d'un champ Nvarparar (max). Il semble fonctionner assez bien mais peut-être qu'une fois que toute la table est chargée en mémoire.

Voici le dbfiddle: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=2CE135DC37D72F9DB951BBB4E2708BAA

5
Giox

Quel meilleur moyen que de tester?

TL: Dr Upt Front. La façon dont vous structurez vos données le rend gênant lorsqu'il existe plusieurs conditions, car vous devez vérifier différentes lignes pour la même réponse. ColumnStore fonctionne mieux simplement pour utiliser Mode batch dans l'auto rejoindre de mon requête de test.

Je m'attendrais à ce que vous obteniez beaucoup plus de structurer vos données de manière différente de la recherche d'options de stockage.

Voici une configuration avec des lignes de 5 m et un exemple de requête à la fin à la recherche d'un âge moyen des personnes dans le centre-ville pour une gamme de réponses (en supposant une enquête particulière). lien dbfiddle aussi

DROP TABLE IF EXISTS dbo.AnswersRow

CREATE TABLE AnswersRow (
ResponseID INT NOT NULL,
QuestionID INT NOT NULL,
AnswerValueText VARCHAR(20) NULL,
AnswerValueDecimal DECIMAL(15,2) NULL,
CONSTRAINT PK_R_Q PRIMARY KEY CLUSTERED (ResponseID,QuestionID)
)

INSERT dbo.AnswersRow
SELECT TOP 5000000
FLOOR((-1+ROW_NUMBER() OVER(ORDER BY(SELECT 'Joe')))/5+1) AS ResponseID,
(-1+ROW_NUMBER() OVER(ORDER BY(SELECT 'Joe')))%5+1 AS QuestionID,
NULL AS AnswerValueText,
NULL AS AnswerValueDecimal
FROM master.dbo.spt_values a
CROSS JOIN master.dbo.spt_values b

--5 questions
--1) Married 0 or 1
--2) BuildingType
--3) CityArea
--4) Age
--5) Income

--randomize answers
UPDATE ar
SET AnswerValueText = CASE
WHEN QuestionID = 2 THEN (CASE x2.seed
                            WHEN 0 THEN 'Concrete'
                            WHEN 1 THEN 'Skeleton'
                            WHEN 2 THEN 'Eternite Sheets'
                            WHEN 3 THEN 'Iron Sheets'
                            WHEN 4 THEN 'Other'
                            END)
WHEN QuestionID = 3 THEN (CASE x3.seed
                            WHEN 0 THEN 'North'
                            WHEN 1 THEN 'South'
                            WHEN 2 THEN 'East'
                            WHEN 3 THEN 'West'
                            WHEN 4 THEN 'Center'
                            END)
ELSE AnswerValueText END,
ar.AnswerValueDecimal = CASE
WHEN QuestionID = 1 THEN (FLOOR(Rand(CONVERT(BINARY(8),NEWID()))*2))
WHEN QuestionID = 4 THEN (FLOOR(Rand(CONVERT(BINARY(8),NEWID()))*60+17))
WHEN QuestionID = 5 THEN (FLOOR(Rand(CONVERT(BINARY(8),NEWID()))*200000))
ELSE AnswerValueDecimal END
FROM dbo.AnswersRow ar
CROSS APPLY (SELECT FLOOR(Rand(CONVERT(BINARY(8),NEWID()))*5) AS seed) x2
CROSS APPLY (SELECT FLOOR(Rand(CONVERT(BINARY(8),NEWID()))*5) AS seed) x3

SELECT *
INTO dbo.AnswersCol
FROM dbo.AnswersRow

CREATE CLUSTERED COLUMNSTORE INDEX CX_Answers ON dbo.AnswersCol
CREATE NONCLUSTERED INDEX IX_Answer_text ON dbo.AnswersRow(AnswerValueText)
CREATE NONCLUSTERED INDEX IX_Answer_decimal ON dbo.AnswersRow(AnswerValueDecimal)
CREATE NONCLUSTERED INDEX IX_Answer_question ON dbo.AnswersRow(QuestionID) INCLUDE(AnswerValueText,AnswerValueDecimal)


--average age of particular survey, city center
SELECT AVG(AnswerValueDecimal), COUNT(*)
FROM dbo.AnswersRow ar1
WHERE 1=1
AND ar1.ResponseID >= 100000 AND ar1.ResponseID < 200000
AND ar1.QuestionID = 4
AND EXISTS (SELECT 1
            FROM dbo.AnswersRow ar2
            WHERE ar1.ResponseID = ar2.ResponseID
            AND ar2.QuestionID = 3
            AND ar2.AnswerValueText = 'Center'
            )


SELECT AVG(AnswerValueDecimal), COUNT(*)
FROM dbo.AnswersCol ar1
WHERE 1=1
AND ar1.ResponseID >= 100000 AND ar1.ResponseID < 200000
AND ar1.QuestionID = 4
AND EXISTS (SELECT 1
            FROM dbo.AnswersCol ar2
            WHERE ar1.ResponseID = ar2.ResponseID
            AND ar2.QuestionID = 3
            AND ar2.AnswerValueText = 'Center'
            )
3
Forrest