9
votes

Conception de la base de données: remplacez une colonne booléenne avec une colonne TIMESTAMP?

Plus tôt, j'ai créé des tables de cette façon: xxx

colonne is_finished indique si le flux de travail est terminé ou non. Colonne Date_finished est lorsque le flux de travail a été terminé.

alors j'ai eu l'idée "Je n'ai pas besoin de no_finished comme je peux simplement dire: où data_finished n'est pas null", et j'ai conçu sans colonne Is_Finished: xxx

(nous utilisons Oracle 10)

est-ce une bonne ou une mauvaise idée? J'ai entendu dire que vous ne pouvez pas avoir un index sur une colonne avec des valeurs null, donc où data_finished n'est pas null sera très lent sur les gros tables.


1 commentaires

Combien de rangées y aura-t-il dans la table en général? Et combien de ceux-ci ne seront pas finis?


10 Réponses :


15
votes

Est-ce une bonne ou une bonne idée?

bonne idée.

Vous avez éliminé l'espace pris par une colonne redondante; La colonne Date sert Double Duty - Vous savez que le travail était terminé et quand .

J'ai entendu dire que vous ne pouvez pas avoir d'index sur une colonne avec des valeurs null, donc "où data_finished n'est pas null" sera très lent sur les gros tables.

c'est incorrect. Les index Oracle ignorent les valeurs null.

Vous pouvez créer un index basé sur la fonction afin de contourner les valeurs NULL non indexées , mais la plupart des dabas que j'ai rencontrés vraiment ne les aimez pas, vous êtes donc prêt pour un combat.


10 commentaires

Wow, désolé mon commentaire n'était pas assez rapide pour vous.


Vous économisez sans espace, en fait, vous perdez beaucoup plus d'espace. Vous faites également les données incompréhensibles que c'est une réponse perdue.


@Stephalie Page: Impossible de gaspiller ce que vous n'utilisez plus, alors comment venez-vous à la conclusion qui vous débarrasse de l'espace des déchets de colonne redondants? La colonne Date est appelée fini_date - à nouveau, comment est-ce incompréhensible?


Il y avait trop de choses à mettre dans un commentaire, je devais ajouter une réponse.


Juste un commentaire sur l'espace sauvé. Disons que la colonne Nombre prend 4 octets (il ne devrait que 1 octet uniquement pour 0/1). Donc, pour un million d'enregistrements qui seront ~ 4MB Wichi est <1 $. Pas une énorme sauvegarde imho! En ce qui concerne les requêtes, is_finished = 0 ou date_finished est null, je dirais que c'est un goût personnel.


Dont le goût? Une base de données n'est pas pour vous le développeur / architecte. C'est pour tout le monde. Vos données surviendront aux applications à chaque fois. Null ne veut rien dire, Nada, Zilch. Dire que cela signifie que le travail est effectué sera déroutant à un moment donné à quelqu'un. Garanti. Is_unfinished = 'Oui' ne sera pas déroutant à personne.


+1 Utilisation des index basés sur la fonction Pour choisir quelques valeurs NULL dans la colonne accélérera les requêtes tant qu'ils utilisent la même expression que celle utilisée pour générer l'index basé sur la fonction.


Bonne idée. Si vous n'avez que le champ booléen, vous perdez des informations critiques. Si vous mettez la colonne Date_finished, il est facile à comprendre et à interroger et à faire une meilleure représentation du monde réel: si c'est NULL, cela signifie simplement qu'il n'a pas été terminé. Avoir deux champs n'est pas normalisé (d'avoir IS_FINED et DATE_FINIPLISÉ): Il est redondant et la redondance conduit à une incohérence (c'est-à-dire que vous pouvez avoir des valeurs incohérentes dans une rangée) et un manque de confiance dans les données et les préquêtes et programmes encastrés par défaillance.


Je vois trois conditions: (1) Si c'est fini, vous savez quand c'est fini et que vous stockez cette valeur. (2) Si cela n'est pas terminé, vous n'avez pas la date d'heure de fin, vous stockez NULL. (3) Vous ne savez pas si cela est terminé ou non, vous stockez euh, quelque chose. Il me semble que le problème est le suivant "Quels aspects de la réalité modélisez-vous dans votre base de données"? Devez-vous être capable de suivre les trois états des trois états possibles ou ne sera-t-il que les deux discussions sur le modèle? Plus au point, comment vos utilisateurs savent-ils comment interpréter vos données? Est-ce qu'ils devinent ou ont-ils lu votre documentation?


Je conviens que la clarté est importante, mais je doute que cela ne soit pas clair. En utilisant une date nulle pour indiquer qu'un événement n'a pas été survenu, c'est une pratique courante et sera comprise par quelqu'un à autre chose. finition_date est null signifie que ce n'est pas fini. En outre, dans une DB, la redondance est le plus gros péché. Votre modèle de DB doit être aussi robuste que possible et la redondance quitte la place pour une incohérence.



3
votes

En termes de conception de la table, je pense qu'il est bon que vous ayez supprimé la colonne comme vous avez dit qu'il n'est pas nécessaire (c'est redondant). Il n'est pas nécessaire de stocker des données supplémentaires si ce n'est pas nécessaire, cela gaspille simplement de l'espace. En termes de performance, je ne vois pas cela étant un problème pour les valeurs nulles. Ils devraient être ignorés.


0 commentaires

0
votes

comme alternative à un index basé sur la fonction, vous pouvez également utiliser une valeur "mannequin" (telle que le 31 décembre 9999, ou alternativement une journée avant la date prévue de la valeur de la date_date_furée) comme la valeur datée_fine pour les flux de travail inachevés.

EDIT: Valeur de date factice alternative, suivant les commentaires.


3 commentaires

Les valeurs factices sont plutôt dangereuses en raison des problèmes qu'ils provoquent pour l'optimiseur. Avec les statistiques les plus fondamentales, si Oracle sait que le Min Date_Finished est, dire, 2009-12-31, et le max date_finished est 9999-12-31, il va supposer qu'une requête pour toutes les lignes terminées en 2010 reviendrait 1/7990 e des données du tableau qui est presque certainement grossièrement incorrecte. Si vous êtes prudent de rassembler des histogrammes constamment, vous pouvez atténuer le problème, mais cela reviendra de vous mordre au moment le moins opportun.


Ma réaction gut est "Ick!". (D'autre part, je ne pense pas que ce soit une mauvaise réponse, juste un seul que je n'utiliserais pas personnellement). En utilisant une valeur par défaut pour indiquer que quelque chose ne contient pas de valeur significative est généralement semé de péril, surtout lorsqu'il s'agit de maintenance. L'expérience me dit que si une colonne ne contient pas de valeur significative, elle devrait être laissée null.


En règle générale, je suis d'accord, Bob, mais dans ce cas, il y a la question des performances lors de l'accès aux flux de travail inachevés.



2
votes

J'utiliserais des nulls comme fonctionne des index, comme déjà mentionné dans d'autres réponses, pour toutes les requêtes, à l'exception de "où date_finished est null" (cela dépend donc si vous devez utiliser cette requête). Je n'utiliserais certainement pas les valeurs aberrantes comme l'année 9999 comme suggérée par la réponse:

Vous pouvez également utiliser une valeur "mannequin" (telle que le 31 décembre 9999) comme valeur Date_finished pour les flux de travail inachevés

Les valeurs aberrantes telles que l'année 9999 affectent les performances, car (de http://richardfoote.wordpress.com/2007/12/13/outlier-values-an-enemy-f-the-index/ ):

La sélectivité d'une plage de plage est essentiellement calculée par le CBO pour être le nombre de valeurs dans la plage d'intérêt divisé par la gamme complète des valeurs possibles (c.-à-d. . La valeur max moins la valeur min)

Si vous utilisez une valeur de 9999, la DB pensera que la plage de valeurs étant stockée dans le champ est par exemple. 2008-9999 plutôt que le réel 2008-2010; Donc, toute requête de gamme (par exemple, entre 2008 et 2009 ») semblera couvrant un tout petit% de la gamme de valeurs possibles, vs couvrant environ la moitié de la plage. Il utilise cette statistique pour dire, si le% des THS éventuelles valeurs couvertes est élevé, de nombreuses lignes correspondent probablement, puis une numérisation de table complète sera plus rapide qu'une analyse de l'index. Cela ne le fera pas correctement s'il ya des valeurs aberrantes dans les données.


1 commentaires

Dans ce cas particulier, je pense qu'il serait plus important de pouvoir sélectionner des flux de travail inachevés, que ceux qui ont été terminés dans une plage de données spécifique. Il serait peut-être possible de combiner la réponse d'OMG avec le commentaire de Justin sur ma réponse - Demandez à la DBAS de configurer un index basé sur la fonction et de les menacer avec le maintien des histogrammes autrement!



4
votes

à tous ceux qui ont dit que la colonne est un gaspillage d'espace:

double devoir n'est pas une bonne chose dans une base de données. Votre objectif principal devrait être clarté. Beaucoup de systèmes, d'outils, de personnes utiliseront vos données. Si vous déguisez les valeurs en enterrant un sens à l'intérieur d'autres colonnes, vous mendez pour un autre système ou l'utilisateur de la tromper.

Et quiconque pense que cela sauve que l'espace est tout à fait faux.

Vous aurez besoin de deux index sur cette colonne de date ... une fonction sera basée sur OMG. Il ressemblera à ceci:

nvl (date_finished, to_date ('01 -Jan-9999 '))

Pour trouver des emplois inachevés, vous devrez vous assurer d'écrire le où la clause correctement

il ressemblera à ceci:

où Nvl (date_finished, to_date ('01 -Jan-9999 ')) = to_date ('01 -JAN-9999')

Yep. C'est tellement clair. C'est complètement meilleur que

où Is_unfinished = 'oui'

La raison pour laquelle vous voudrez avoir un deuxième index sur la même colonne est pour toutes les autres questions à cette date ... Vous ne voudrez pas utiliser cet index pour trouver des emplois par date.

Voyons donc ce que vous avez accompli avec la suggestion d'OMG et al.

Vous avez utilisé plus d'espace, vous avez obtenu la signification des données, vous avez obtenu J'ai fait des erreurs plus probables ... gagnant!

Il semble que les programmeurs vivent toujours dans les années 70 lorsqu'un MB d'espace disque était un acompte sur une maison.

vous Peut être un espace efficace à ce sujet sans abandonner beaucoup de clarté. Effectuez l'IS_Unfinished Y ou Null ... si vous n'utiliserez que cette colonne pour trouver «travail à faire». Cela gardera cet index compact. Ce ne sera que aussi gros que des rangées non finies (de cette façon, vous exploiterez les nulls non indexés au lieu d'être vissé par celui-ci). Vous mettez un peu d'espace dans votre table, mais sur tout ce que c'est moins que le FBI. Vous avez besoin d'un octet pour la colonne et vous n'exprimez que les lignes inachevées afin que «une petite fraction de travail et reste probablement assez constante. Le FBI aura besoin de 7 octets pour chaque ligne, que vous essayiez de les trouver ou non. Cet indice restera en rythme de la taille de la table, pas seulement la taille des travaux inachevés.

Répondre au commentaire de omg

dans son commentaire il / elle déclare que pour trouver des emplois inachevés, vous utiliseriez simplement xxx

mais dans sa réponse, il dit

Vous pouvez créer un index basé sur la fonction afin de contourner les valeurs NULL non indexées

Si vous suivez le lien, il vous indique, à l'aide de NVL pour remplacer les valeurs null avec une autre valeur arbitraire, je ne suis pas sûr de quoi il doit expliquer.


8 commentaires

Pour trouver des travaux inachevés, vous n'utilisez que où date_finished est null . Vous ne parvenez pas à expliquer où l'espace est gaspillé - vous venez de vous promener sur le besoin de deux index. Et il n'y a rien qui démontre qu'une colonne de date nullable est obscurcante des données.


Je conviendrais avec vous Stephanie dans une mesure, mais dans ce cas, c'est assez évident. Je pense (et ceci, bien sûr, est une opinion) que la plupart des développeurs intuit que "Date_Finished est NULL" signifie que "il n'y a pas de date à laquelle il était terminé, cela signifie que cela n'a pas été fini". Si une colonne Y / N supplémentaire est nécessaire, il faudrait réfléchir au cas par cas, IMHO.


J'entends ce que tu dis, mais tu as dit "la plupart". Cela signifie qu'il y en a une chose qui ne le fera pas. Cela signifie qu'il y a un potentiel d'interprétation erronée, de malentendus, etc. et pourquoi seuls que seuls les développeurs toucheront jamais les données. Et s'il y a un rapport qui doit être passé de là pour des personnes d'affaires? Donc, maintenant, vous allez espérer qu'ils interprètent également l'endroit vide dans la colonne Date_Finished, car il est toujours en cours d'exécution ou que vous allez calculer cette colonne en tant que NVL2 (date_finished, 'n', 'y') est_unfinished. Pourquoi ne pas simplement le sélectionner?


En outre, vous n'économisez toujours aucun espace. Même si vous utilisez un FBI plus intelligent (voir tinyurl.com/nullindexes ) que l'article OMG Linked suggère l'utilisation, la Extra, 0) Dans l'index prend autant d'espace que la colonne. Au moins dans mes calculs sur une table de 1 mm.


@Stephanie - Pourquoi ne pouvez-vous pas créer de vue appelé Vcompletedworkflow qui filtre toutes les valeurs null et dire aux gens d'affaires d'utiliser ce point de vue pour leurs rapports?


@KP - ohmmmmmmmm ohmmmmmmmm vues est mon ami. Ohmmmmmmm ohmmmmmmmmmmmmmmm


Gunny, bien d'abord, vous n'essayez pas de filtrer le NULL, vous essayez de filtrer les NOT NULLS. Une fois que le travail a un temps terminé, c'est-à-dire Not NULL, il est considéré comme terminé. Mais pourquoi? Et puis vous aurez également besoin d'une vue pour ingâblie_work_flow, puis une vue pour tous les flux de travail. Droit? Ou allez-vous autoriser directement l'accès à la vue et à la table? Et c'est moins déroutant? Et tout cela dans un effort pour éviter une colonne qui rend vos données claires? Ce n'est pas-il 80 et ce n'était clairement pas une application haute performance ou il n'utilisait jamais une table pour cela.


À moins d'une situation définie dans laquelle un flux de travail peut être terminé sans que sa date soit connue, je vous fierais à la colonne Date, et peut-être une colonne virtuelle (11g +) pour indiquer "fini ou non". Il est vrai que l'espace disque est bon marché, mais les données sont maintenant moins chères, et nous traitons souvent des systèmes avec beaucoup plus que même il y a 10 ans. Au fait, n'oubliez pas que le Rowid dans le bloc de feuille d'index représente 12 octets (comme je me souviens), quelle que soit la longueur des données indexées.



0
votes

Je préfère la solution à colonne unique.

Toutefois, dans les bases de données, j'utilise le plus souvent des nuls sont inclus dans les index, votre cas de recherche de flux de travail ouverte sera donc rapide alors que dans votre cas, il sera plus lent. Étant donné que le cas de la recherche de flux de travail ouverts est probablement l'une des choses les plus courantes que vous faites, vous aurez peut-être besoin de la colonne redondante simplement pour soutenir cette recherche.

Test de la performance Pour savoir si vous pouvez utiliser la meilleure solution de performance, puis retombez à la solution moins bonne si nécessaire.


0 commentaires

1
votes

bonne idée de supprimer la colonne de valeur dérivée, car d'autres ont dit.

Une pensée de plus est que, en supprimant la colonne, vous éviterez des conditions paradoxales que vous devrez codir, telles que ce qui se passe lorsque l'IS_FINED = NO et le fini_Date = hier ... etc.


0 commentaires

5
votes

Est-ce une bonne ou une bonne idée? J'ai entendu dire que vous ne pouvez pas avoir un index sur une colonne avec des valeurs null, donc "où data_finished n'est pas null" sera très lent sur les gros tables.

oracle fait l'index champs nullables , mais n'expose pas null valeurs

Ceci signifie que vous pouvez créer un index sur un champ marqué null , mais les enregistrements tenant null dans ce champ ne le feront pas dans l'index.

Ceci, à son tour , signifie que si vous faites date_fine null , l'index sera moins en taille , car les valeurs null ne seront pas stockées dans l'index .

de sorte que les requêtes impliquant une recherche d'égalité de portée sur date_finisheished fonctionneront en fait mieux.

La baisse de cette solution est bien sûr que le Queries impliquant les valeurs null de dat_finished devront revenir à la numérisation de la table complète.

Vous pouvez contourner cela en créant deux index: xxx

et utilisez cette requête pour trouver un travail inachevé: xxx

Ceci se comportera comme index partitionné: les travaux complets seront indexés par le premier index; Les incomplets seront indexés par la seconde.

Si vous n'avez pas besoin de rechercher des œuvres complètes ou incomplètes, vous pouvez toujours vous débarrasser des index appropriés.


2 commentaires

Indexation pour la recherche sur Date_Finished = NULL est une optimisation. (Intuitivement, cela est susceptible d'être nécessaire car des données sont ajoutées.) La colonne IS_FINÉE est également une optimisation car elle est dérivée de date_finished. L'indice basé sur la fonction est susceptible de causer moins de problèmes. Le défaut de l'utiliser dans une requête se dégradera dans une recherche non indexée et il n'y a aucun risque d'informations contradictoires comme avec IS_FINED et DATE_FINIPHIQUE.


J'ajouterais que les champs booléens font de petits index usagés. À moins que la ration de true to faux ne soit quelque chose comme 10 à 1, l'optimiseur ignorera l'index et (tout à fait) optera pour une balayage d'espace de table ou, espérons-le, un autre index.



11
votes

Il existe un droit moyen d'indexer les valeurs null, et il n'utilise pas de FBI. Oracle indexez les valeurs NULL, mais il n'indore pas les valeurs de feuilles nulles dans l'arborescence. Donc, vous pourrait éliminer la colonne is_finished et créer l'index comme celui-ci. XXX

Puis, si vous vérifiez le plan d'explication sur cette requête: xxx

Vous pouvez voir l'index utilisé (si l'optimiseur est heureux).

retour à la question initiale: regarder la variété de Réponses ici, je pense qu'il n'y a pas droite réponse. Je peux avoir une préférence personnelle pour éliminer une colonne si elle est inutile, mais je n'aime pas non plus surcharger la signification des colonnes non plus. Il y a deux concepts ici:

  1. L'enregistrement est terminé. is_finished
  2. L'enregistrement est terminé à une date donnée. Date_Finished

    Peut-être que vous devez garder ces distincts, peut-être que vous ne le faites pas. Quand je pense que l'élimination de la colonne is_finished , cela me dérange. Down the Road, la situation peut survenir où l'enregistrement est terminé, mais vous ne savez pas précisément quand. Peut-être que vous devez importer des données d'une autre source et la date est inconnue. Bien sûr, ce n'est pas dans les exigences de l'entreprise maintenant, mais les choses changent. Que faites-vous alors? Eh bien, vous devez mettre une valeur nominale dans la colonne Date_Finished et vous avez maintenant compromis les données un peu. Pas horriblement, mais il y a un frottement là-bas. La petite voix dans ma tête est de crier vous le faites mal quand je fais des choses comme ça.

    Mon conseil, gardez-le séparément. Vous parlez d'une colonne minuscule et d'un index très maigre. Le stockage ne doit pas être un problème ici.

    règle de représentation: connaissances pliales dans les données afin que la logique de programme puisse être stupide et robuste.

    -S. S. Raymond


2 commentaires

Il n'est pas clair pour moi de savoir si vous voulez dire qu'un index sur (date_finished, 1) est ou n'est pas basé sur la fonction. Cependant, pour le dossier Oracle considère qu'en tant qu'index fondé sur la fonction.


Oui vous avez raison. J'étais inexact lorsque j'ai déclaré que ma solution n'utilise pas de FBI. Ce que je devrais dire, c'est que je ne manipule pas la colonne que je tente d'indexer.



1
votes

Pour résoudre les colonnes indexées / non indexées, ne serait-il pas plus facile de simplement rejoindre deux tables, comme celui-ci: XXX

Ainsi, si un enregistrement existe dans Workflow_Finished, ce flux de travail terminé, sinon ce n'est pas le cas. Il me semble plutôt simple.

Lors de la requête pour des flux de travail inachevés, la requête devient: xxx

peut-être que vous voulez peut-être la requête originale? Avec un drapeau et la date? Requête comme ça alors: xxx

pour les consommateurs des données, les vues peuvent et doivent être créées pour leurs besoins.


0 commentaires