4

J'ai un développeur en herbe qui est très enthousiaste au sujet de ce qu'il appelle « la matrice »SQL Server 2008 - Trop de dénormalisation et d'indexation excessive: à quoi sert la matrice?

Je cherche un aperçu des pairs

En un mot c'est ce que nous avons:
- 1 table très dénormaliser avec environ 120 colonnes
- les points de données vont de compte, client, ménage, relation, produits, employés, etc ...
- Un index par colonne: environ 120 index non cluster
- environ 90% de tout l'espace dans la base de données utilisée par les index aujourd'hui sont des index sur cet onglet le
- Aujourd'hui, environ 1,5 millions de lignes avec beaucoup de valeurs nulles
- table chargée d'une procédure stockée dont le noyau est SQL
dynamique - noms Tous sur le terrain sont génériques et ne décrivent pas les données
- Une table de type dictionnaire de données est utilisé avec le SQL dynamique pour charger un point de données à un champ
- la cartographie sur le terrain n'est pas statique: colonne aujourd'hui dim_0001 est le nom du client, mais demain peut-être quelque chose d'autre
- pas de clé primaire
- pas de clés étrangères
- Aucune contrainte réelle (Par exemple, tous les champs sont nullables)

L'argument de la table:
- rend l'écriture des requêtes simples, car il élimine les besoins d'écrire certains rejoindre

L'utilisation prévue:
- une couche utilisateur final et serait une composante essentielle d'un univers build dans Business Objects
- Développement de processus post-ETL

Ma recommandation va soit tuer le processus où il est aujourd'hui (début de développement dans un environnement de test) ou passer à l'étape suivante du test. Selon les recherches que j'ai faites, mes études et mon expérience, je ne le supporte pas et je souhaite que les tables soient abandonnées dès que le ou les processus qui dépendent de ces tables ont été migrés vers une autre solution.

Script ci-dessous pour votre référence (je me suis limité à un exemple d'index).

Toute idée que vous pouvez offrir (même juste une opinion de mot) est précieux

-- The Matrix 

CREATE TABLE [z005497].[tblMatrix](
    [as_of_dt] [datetime] NOT NULL, 
    [dim_0001] [varchar](100) NULL, 
    [dim_0002] [varchar](103) NULL, 
    [dim_0003] [varchar](100) NULL, 
    [dim_0004] [varchar](100) NULL, 
    [dim_0005] [varchar](100) NULL, 
    [dim_0006] [varchar](100) NULL, 
    [dim_0007] [varchar](100) NULL, 
    [dim_0008] [varchar](100) NULL, 
    [dim_0009] [varchar](100) NULL, 
    [dim_0010] [varchar](100) NULL, 
    [dim_0011] [varchar](100) NULL, 
    [dim_0012] [varchar](100) NULL, 
    [dim_0013] [varchar](100) NULL, 
    [dim_0014] [varchar](100) NULL, 
    [dim_0015] [varchar](100) NULL, 
    [dim_0016] [varchar](100) NULL, 
    [dim_0017] [varchar](103) NULL, 
    [dim_0018] [varchar](103) NULL, 
    [dim_0019] [varchar](103) NULL, 
    [dim_0020] [varchar](103) NULL, 
    [dim_0021] [varchar](103) NULL, 
    [dim_0022] [varchar](103) NULL, 
    [dim_0023] [varchar](103) NULL, 
    [dim_0024] [varchar](103) NULL, 
    [dim_0025] [varchar](103) NULL, 
    [dim_0026] [varchar](11) NULL, 
    [dim_0027] [varchar](11) NULL, 
    [dim_0028] [varchar](11) NULL, 
    [dim_0029] [varchar](11) NULL, 
    [dim_0030] [varchar](11) NULL, 
    [dim_0031] [varchar](11) NULL, 
    [dim_0032] [varchar](11) NULL, 
    [dim_0033] [varchar](11) NULL, 
    [dim_0034] [varchar](11) NULL, 
    [dim_0035] [varchar](11) NULL, 
    [dim_0036] [varchar](11) NULL, 
    [dim_0037] [varchar](11) NULL, 
    [dim_0038] [varchar](11) NULL, 
    [dim_0039] [varchar](11) NULL, 
    [dim_0040] [varchar](11) NULL, 
    [dim_0041] [varchar](11) NULL, 
    [dim_0042] [varchar](11) NULL, 
    [dim_0043] [varchar](11) NULL, 
    [dim_0044] [varchar](11) NULL, 
    [dim_0045] [varchar](11) NULL, 
    [dim_0046] [varchar](11) NULL, 
    [dim_0047] [varchar](11) NULL, 
    [dim_0048] [varchar](11) NULL, 
    [dim_0049] [varchar](11) NULL, 
    [dim_0050] [varchar](11) NULL, 
    [dim_0051] [varchar](11) NULL, 
    [dim_0052] [varchar](11) NULL, 
    [dim_0053] [varchar](11) NULL, 
    [dim_0054] [varchar](5) NULL, 
    [dim_0055] [varchar](5) NULL, 
    [dim_0056] [varchar](5) NULL, 
    [dim_0057] [varchar](5) NULL, 
    [dim_0058] [varchar](5) NULL, 
    [dim_0059] [varchar](5) NULL, 
    [dim_0060] [varchar](5) NULL, 
    [dim_0061] [varchar](5) NULL, 
    [dim_0062] [varchar](5) NULL, 
    [dim_0063] [varchar](5) NULL, 
    [dim_0064] [varchar](5) NULL, 
    [dim_0065] [varchar](5) NULL, 
    [dim_0066] [varchar](5) NULL, 
    [dim_0067] [varchar](5) NULL, 
    [dim_0068] [varchar](5) NULL, 
    [dim_0069] [varchar](5) NULL, 
    [dim_0070] [varchar](5) NULL, 
    [dim_0071] [varchar](5) NULL, 
    [dim_0072] [varchar](5) NULL, 
    [dim_0073] [varchar](5) NULL, 
    [dim_0074] [varchar](5) NULL, 
    [dim_0075] [varchar](5) NULL, 
    [dim_0076] [varchar](5) NULL, 
    [dim_0077] [varchar](5) NULL, 
    [dim_0078] [varchar](5) NULL, 
    [dim_0079] [varchar](5) NULL, 
    [dim_0080] [varchar](5) NULL, 
    [dim_0081] [varchar](5) NULL, 
    [dim_0082] [varchar](5) NULL, 
    [dim_0083] [varchar](5) NULL, 
    [dim_0084] [int] NULL, 
    [dim_0085] [int] NULL, 
    [dim_0086] [int] NULL, 
    [dim_0087] [int] NULL, 
    [dim_0088] [int] NULL, 
    [dim_0089] [int] NULL, 
    [dim_0090] [int] NULL, 
    [dim_0091] [int] NULL, 
    [dim_0092] [int] NULL, 
    [dim_0093] [int] NULL, 
    [dim_0094] [varchar](12) NULL, 
    [dim_0095] [varchar](12) NULL, 
    [dim_0096] [varchar](12) NULL, 
    [dim_0097] [varchar](120) NULL, 
    [dim_0098] [varchar](120) NULL, 
    [dim_0099] [varchar](120) NULL, 
    [dim_0100] [numeric](20, 0) NULL, 
    [dim_0101] [varchar](20) NULL, 
    [dim_0102] [varchar](20) NULL, 
    [dim_0103] [varchar](20) NULL, 
    [dim_0104] [varchar](20) NULL, 
    [dim_0105] [varchar](20) NULL, 
    [dim_0106] [varchar](20) NULL, 
    [dim_0107] [varchar](20) NULL, 
    [dim_0108] [varchar](20) NULL, 
    [dim_0109] [varchar](20) NULL, 
    [dim_0110] [varchar](20) NULL, 
    [dim_0111] [varchar](20) NULL, 
    [dim_0112] [varchar](20) NULL, 
    [dim_0113] [varchar](20) NULL, 
    [dim_0114] [varchar](20) NULL, 
    [dim_0115] [varchar](20) NULL, 
    [dim_0116] [varchar](20) NULL, 
    [dim_0117] [varchar](20) NULL, 
    [dim_0118] [varchar](20) NULL, 
    [dim_0119] [varchar](20) NULL, 
    [dim_0120] [varchar](20) NULL, 
    [lastLoad] [datetime] NULL 
) ON [PRIMARY] 



-- Index example 

CREATE NONCLUSTERED INDEX [idx_dim_0001 (not unique)] ON [z005497].[tblMatrix] 
(
    [dim_0001] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 


-- The configuration table from which developers would find out what is in the Matrix 

CREATE TABLE [z005497].[tblMatrixCfg](
    [dimId] [int] IDENTITY(100000,1) NOT NULL, 
    [colName] [varchar](25) NOT NULL, 
    [dataType] [varchar](25) NOT NULL, 
    [dimName] [varchar](25) NOT NULL, 
    [dimDesc] [varchar](500) NOT NULL, 
    [dimpath] [varchar](5000) NOT NULL, 
    [loadDate] [datetime] NOT NULL, 
    [modUser] [varchar](100) NOT NULL, 
    [modDate] [datetime] NOT NULL, 
CONSTRAINT [PK_tblMatrixCfg_1] PRIMARY KEY CLUSTERED 
(
    [dimId] ASC, 
    [colName] ASC, 
    [dimName] ASC 
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
) ON [PRIMARY] 
+1

[Ce n'est pas exactement votre modèle matriciel mais il a quelques similitudes et devrait être un conte d'avertissement!] (Http: //www.simple-talk.com/opinion/opinion-pieces/bad-carma /) –

+1

Merci Martin ... il y a tellement de parallèles avec ce que nous traversons sur cette construction. Cette citation résume bien la situation: "La qualité, la flexibilité et la qualité des systèmes Vision étaient moins importantes pour Upstart en tant qu'entreprise, malgré leur attractivité pour la division informatique d'Upstart, elle était assez fiable, mais elle n'avait pas la vitesse pour remplir ses objectifs. Ceci est un exemple classique de ce qui peut arriver lorsque les priorités du département informatique ne correspondent pas, et ne sont pas alignées, sur les priorités du «business». –

Répondre

7

Tuez-le si vous le pouvez.

En outre, ce développeur a besoin de beaucoup plus d'expérience. Et il/elle devrait l'obtenir dans une autre entreprise.

C'est fondamentalement violer tellement de choses que je ne sais pas par où commencer.

Même si vous finissez par combattre un modèle hautement normalisé qui suit servilement les meilleures pratiques de quelqu'un, il ne sera pas comparable au désastre que ce modèle va créer.

+0

Merci Cade, j'apprécie votre avis ... Je suis un greenhorn stackoverflow ... en regardant vos questions maintenant pour voir si je peux ajouter une valeur –

+0

Les noms de champs génériques sont vendus comme une fonctionnalité, mais semblent être exagérés parce qu'une fois qu'un processus dépend d'un champ, il peut ne changez pas dynamiquement de toute façon (sans changer le processus) –

+1

@santiago_jon Je ne voudrais même pas entrer dans une discussion sur les pratiques de ce développeur Je recommande pour le cycle de vie d'une application basée sur cette architecture de base de données - vous voyez des choses comme ça occasionnellement à propos et ça finit toujours en larmes. Des trucs comme celui-ci et des modèles EAV (qui ont leur place dans des sous-systèmes spéciaux) ont tendance à se faire avec des développeurs qui veulent écrire "The Last Database" - http://en.wikipedia.org/wiki/The_Last_One_(software) –

5

Juste pour donner un exemple de ce que Cade signifiait avec « Je ne sais pas où commencer »:

« dim_0001 colonne aujourd'hui est le nom du client, mais demain peut-être quelque chose d'autre »

Ce généralement aussi signifie que dans le système d'acceptation de l'utilisateur, dim_0001 peut être le nom du client (et le système peut sembler fonctionner et être accepté), puis vous passez à la production, et dim_0001 devient le nom de la femme du président, et ensuite les réunions doivent être consacrées à essayer de comprendre (a) où est le problème, et (b) comment le faire réparer le plus rapidement possible.

((b) revient généralement à patcher le code avec des trucs comme « si column_name = dim_0001 alors ne traitent pas comme ce que la matrice est dit, mais le traiter comme ce qui est ici au lieu hardcoded ».)

+0

Merci Erwin. En parlant avec le développeur, il a mentionné que l'idée de colonnes nommées génériquement lui venait en partie en regardant quelques-unes de nos tables de configuration. Par exemple: un tableau qui pourrait fournir une description de méthode conviviale pour l'entreprise sur un rapport de synthèse des résultats du traitement. Dans quelques-uns de ces tableaux, nous avons un petit nombre de colonnes "juste au cas" qui sont prêtes quand quelqu'un d'important du côté des entreprises se lève et dit "hé, je le veux comme ça maintenant". Exemples: "AltDesc1" (Alternate Description Alternate 1) et "AltDesc2" (Alternate Description 2). –

+0

Lorsqu'on le questionne, le développeur référence cet article Wikipedia (qui a bien sûr la balise Weasel Words): http://en.wikipedia.org/wiki/Enterprise_bus_matrix Cet article semble en grande partie théorique à moi et à mes yeux où il a fini avec la matrice n'est pas vraiment ce que l'auteur décrit. –

+1

@santiago_jon Dans l'entrepôt de données, c'est un outil pour développer le modèle logique. Dans tous les cas, un entrepôt de données n'est généralement pas utilisé pour les données transactionnelles. Il peut être avantageux de modéliser certaines choses sous une forme dimensionnelle, mais cela résout des problèmes très spécifiques, généralement pour des requêtes et des analyses ad hoc. Ce modèle n'est pas un modèle dimensionnel, il ne correspond pas non plus au modèle normalisé typique - le seul précédent pour cela est également des idées mal conçues. –

4

"À quoi sert la matrice?"

Eh bien, je ne comprends certainement pas.

Je n'avais jamais rien vu de tel auparavant et je ne comprends pas comment il doit être utilisé ou comment les index sont destinés à accélérer quelque chose ou comment il est possible d'interroger cette table sans utiliser au moins les auto-jointures . Appelez-moi inexpérimenté si vous aimez mais c'est une première pour moi. Je pense que si c'est la façon de faire les choses, les fournisseurs de db ne devraient pas mettre autant d'efforts pour nous permettre aux développeurs de définir des tables, avec des colonnes qui ont des types de données différents, avec des relations.

+0

Merci Mikael. À ce stade, je suis en mode de contrôle des dommages cherchant à sauver ce que je peux de son travail: il est dans environ 40 heures à ce jour de l'entreprise. Cela me fait me demander combien de connexions il aurait pu écrire avec ces 40 heures. Proabably trois mois de valeur dans notre boutique. C'était un peu le Saint Graal à la fin de cette quête pour lui: éliminez le besoin d'écrire des jointures. Je ne vois toujours pas comment la matrice ferait cela: que se passe-t-il lorsque votre clause WHERE nécessite des critères basés sur des champs non trouvés dans la matrice? N'avez-vous pas à apporter ces tables de toute façon à travers une jointure? On dirait ça. –

+1

@santiago_jon comptez-vous chanceux, il n'a que 40 heures dans ce domaine. –

+0

D'accord. Nous nous soucions du gars et nous voulons qu'il réussisse. Je prévois le rencontrer aujourd'hui et passer en revue les résultats de l'évaluation par les pairs. On dirait que je dois un peu raccourcir la laisse et insister pour qu'il reste concentré sur la nécessité de répondre aux besoins actuels de l'entreprise. Souhaite moi bonne chance! –

1

Ceci est le résultat de la tentative d'insérer un paradigme orienté objet dans un système relationnel. Document databases permettent ce genre de programmation:

documents dans une base de données orientée document sont similaires, dans certains façons, aux dossiers ou des lignes, dans des bases de données relationnelles, mais ils sont moins rigides . Ils ne sont pas tenus d'adhérer à un schéma standard et ne possèdent pas les mêmes sections, emplacements, pièces, clés ou similaires. Pour exemple, voici un document:

FirstName="Bob", Address="5 Oak St.", Hobby="sailing". 

Un autre document pourrait être:

FirstName="Jonathan", Address="15 Wanamassa Point Road", Children=[{Name:"Michael",Age:10}, {Name:"Jennifer", Age:8}, 
{Name:"Samantha", Age:5}, {Name:"Elena", Age:2}]. 

Les deux documents ont des informations similaires et d'autres différents. Contrairement à une base de données relationnelle où chaque enregistrement aurait le même ensemble de champs et les champs inutilisés peuvent être gardés vides, il n'y a pas 'champs' vides dans l'un ou l'autre document (enregistrement) dans ce cas. Ce système permet de nouvelles informations à ajouter et il n'est pas nécessaire d'indiquer explicitement si d'autres informations sont omises.

L'utilisation de ce paradigme dans une base de données relationnelle est un problème de type «carré, trou rond». Une base de données de documents peut être excellente pour un système hautement transactionnel, mais l'analyse serait mieux servie en chargeant les données transactionnelles dans diverses tables de faits dans un entrepôt de données.