Nous avons l'une de ces bogues de corruption des données cryptiques bizarres qui apparaissent toutes les quelques semaines et personne ne sait pourquoi. Jusqu'à présent, il semble que la clé primaire sur une table soit changeante spontanément, de sorte que d'autres lignes qui le pointent sont maintenant gâchées.
Si je cherche toujours la cause fondamentale de ceci (il est impossible de reproduire), Je voudrais qu'une sorte de hack temporaire empêche une valeur de colonne de changer de change. Voici le schéma de la table: p>
CREATE TABLE TPM_INITIATIVES ( INITIATIVEID NUMBER NOT NULL, NAME VARCHAR2(100) NOT NULL, ACTIVE CHAR(1) NULL, SORTORDER NUMBER NULL, SHORTNAME VARCHAR2(100) NULL, PROJECTTYPEID NUMBER NOT NULL, CONSTRAINT TPM_INITIATIVES_PK PRIMARY KEY(INITIATIVEID) NOT DEFERRABLE VALIDATE )
3 Réponses :
masque la table derrière une vue et apporter la mise à jour de la mise à jour de la mise à jour, mais la colonne que vous souhaitez protéger p>
Malheureusement, cela est trop en désordre d'un changement et ne sera pas approuvé pour une base de données de production. Nous avons besoin d'une solution à chaud rapide.
Pourquoi? - Vous modifiez la table
Alors comment gérer update code> s,
Supprimer code> s et
insère code> s avec la vue? Tout le code de l'application utilise SQL brut contre l'ancien nom de table.
Vous faites la vue mise à jour et que vous créez au lieu de déclencheurs pour la vue pour mettre à jour tous les champs, à l'exception de celui que vous ne voulez pas.
Ok, ça a du sens. Merci!
La deuxième option pourrait être meilleure. Si vous avez une table / fichier de journalisation, vous pouvez essayer d'écrire un message avec autant d'informations de diagnostic que possible, chaque fois qu'il y a une tentative de modification de la valeur. P>
S'il y a des tables d'enfants remplacées par des données qui fait référence à la colonne code> initiative code>, Oracle doit automatiquement rendre difficile la modification de la valeur de la clé principale en vous évitant de créer des lignes orphelines en modifiant la clé primaire du parent. Donc, par exemple, s'il existe une table enfant qui a une contrainte de clé étrangère à Si votre application a défini des tables d'enfant, mais non déclarées les contraintes de clé étrangère appropriées, ce serait le meilleur moyen de résoudre le problème. P> Cela étant dit, la solution d'Arnon de création d'une vue devrait fonctionner. Vous renondiez à la table, créez une vue avec le même nom que la table existante, et (potentiellement) définissez un fichier au lieu de déclencher sur la vue qui ne mettrait jamais à jour la colonne Vous pouvez également définir une gâchette sur la table p> Quelqu'un pourrait bien sûr, Désactiver la gâchette et émettre une mise à jour. Mais je suppose que vous n'essayez pas d'arrêter un attaquant, juste un morceau de code buggy. P> basé sur la description de quels symptômes vous voyez, cependant, il semblerait avoir plus de sens à Connectez-vous l'historique des modifications apportées aux colonnes de cette table afin de pouvoir déterminer ce qui se passe plutôt que de deviner et d'essayer de brancher des trous uniques. Donc, par exemple, vous pouvez faire quelque chose comme ça p> alors vous pouvez interroger tpm_initiactives code> et il y a une ligne dans cette table enfant avec un
initiative (code> de 17, vous avez gagné 't être capable de modifier le
initiatived code> de la ligne dans le tableau code> tpm_initiakes code> dont la valeur actuelle est 17. S'il n'y a pas de ligne dans une table enfant qui fait référence à la rangée particulière Dans la table code> TPM_Initiatives code>, vous pouvez modifier la valeur mais, vraisemblablement, s'il n'y a pas de relation, la modification de la valeur de la clé principale est sans importance car elle ne peut pas, par définition, causer un problème d'intégrité des données. Bien sûr, vous pourriez avoir du code qui insère une nouvelle ligne dans
tpm_initiactives code> avec un nouveau
initiative code>, changez toutes les lignes de la table enfant qui font référence à l'ancienne ligne pour faire référence à La nouvelle ligne, puis modifier la vieille rangée. Mais cela ne sera pas piégé par aucune des solutions proposées.
initiative code>. Cela ne devrait pas nécessiter de modifications à d'autres bits de l'application. P>
tpm_initiatiatiets_hist code> pour voir tous les modifications apportées à un particulier à une rangée au fil du temps. Vous pouvez donc voir si les valeurs principales de la clé changent ou si quelqu'un change simplement les champs non clés. Idéalement, vous pouvez avoir des colonnes supplémentaires que vous pouvez ajouter à la table d'historique pour aider à suivre les modifications (c'est-à-dire qu'il y a peut-être quelque chose à partir de
V $ Session code> qui pourrait être utile). P> P> P> P> P> P> P> >
Vous dites si une autre table a une contrainte FK sur initiatived code>, alors oracle ne permettra pas de changer cette touche? Je vérifierai si ces contraintes existent et les ajouterai si non. J'aime l'idée de déclenchement, il semble rapide et facile. Idée de vue, je suis d'accord, serait le meilleur correctif à long terme, mais je suis très nerveux à propos de l'application de ce type de changement en direct sur un serveur de production. Je suppose que je pourrais la tester sur l'un des serveurs de stadification d'abord.
@MIKE CHRISTENSEN - J'ai étendu un peu sur le bit de contrainte de clé étrangère. Oracle ne vous permet pas d'orpheline une ligne d'enfant en modifiant la clé de la ligne parent.
Oh gotcha oui. Je ne crois pas que ces lignes étaient orphelines, mais ce que nous voyions est une rangée d'enfants indiquerait à maîtriser un, puis tout à coup, il serait soudain de pointer le maître B (qui a la même clé que le maître a fait), et Le maître A est maintenant mystérieusement disparu.
@Mikechristensen - Alors pourquoi croyez-vous que le problème est que la clé principale change? Cela ne semblerait-il pas plus probable que quelqu'un mettait la mise à jour des données non clés de la ligne pour le changer de A à B?
C'est une autre possibilité. J'ai examiné le code qui met à jour ces enregistrements et tout semble bien. Cela n'arrive généralement pas, donc c'est une condition de race ou une chose intermittente. C'est pourquoi mon objectif est maintenant d'éliminer autant de possibilités que possible, et peut-être que la cause fondamentale finira par surface.
@Mikechristensen - J'ai mis à jour ma réponse avec une approche différente. Il semble probable que vous souhaitiez vraiment vérifier les modifications apportées aux données afin que vous puissiez analyser les modifications plutôt que de deviner à ce qui pourrait se produire.
Oui ce n'est pas une mauvaise idée du tout. L'insertion des lignes dans une table de journalisation n'est-elle le seul moyen de connecter des données dans Oracle? Je ne peux pas écrire sur un journal ou un fichier d'événements système ni quelque chose?
@Mikechristensen - C'est l'approche la plus facile. Vous pouvez utiliser le package utl_file code> pour écrire dans un fichier sur le système de fichiers, vous pouvez écrire sur le journal d'alerte (bien que cela créerait probablement des maux de tête pour les dabs), vous pouvez éventuellement écrire une ligne à l'opération Journal des événements du système avec une procédure stockée de Java ou .NET appropriée, etc. Mais une table de journaux est la solution la plus simple possible. Vous pouvez utiliser Oracle Workspace Manager pour que Oracle suivre automatiquement l'historique pour vous, qui a beaucoup d'avantages sur des déclencheurs personnalisés, mais qu'il est plus difficile de déposer dans un système en direct.
Faites également attention à la création de lignes en double et à la suppression de l'ancienne rangée.
Oui, je remarquai réellement qu'il y avait une contrainte unique sur
initiatived code> mais que quelqu'un l'avait désactivé (?!?!) - Je suis déjà allé de l'avant et l'a réactivée et vérifiée ça fonctionne, alors j'espère que cela fonctionne. 'll aider ce bug disparaître aussi. Je pense que la prévention des mises à jour de la clé mettra un clou dans le cercueil de ce problème.
OH BTW, le code qui insère de nouvelles lignes est assez abdyssmal. Il fait fondamentalement une `Sélectionnez Max (initiative) des initiatives» et ajoute 1 à cela pour obtenir le nouvel identifiant. Ce n'est complètement pas une transaction sans danger, et c'est vraiment lent. C'est pourquoi j'aime utiliser Uuids pour mes clés, mais ce serait un changement assez massif maintenant.
@Mikechristensen Vous pouvez peut-être requête
user_source code> pour
Sélectionner max (initiative) code> et les remplacer par une séquence ..
Oui, à l'aide d'une séquence, c'est la voie à suivre - toutefois, Oracle ne prend pas en charge automatiquement à l'aide d'une séquence pour une table et je n'ai aucune idée de la procédure d'entité .NET pour utiliser une séquence pour les insertions.