Metadaten-Inkonsistenzen in InterSystems IRIS führen zu unerwarteten Abfrageergebnissen, vermeidbaren Ausnahmen und Daten, die leise aufhören zu bedeuten, was das Schema sagt, dass sie bedeuten. Der frustrierende Teil ist, dass sich nur einer der drei Fehlermodi bemerkbar macht. Die anderen beiden sehen in den meisten SQL-Clients völlig gesund aus. Dieser Artikel geht alle drei durch, unter Verwendung einer Beispieldatenbank, die Sie selbst installieren können, und zeigt, was SQL DATA LENS in jedem Fall aufdeckt.
Das Problem: umgangene Metadatenvalidierung
IRIS lässt Sie die Daten auf zwei Wegen erreichen: durch die relationalen und Objektschichten, die gegen die Klassendefinition validieren, und direkt durch Globals, die es nicht tun. Anwendungen, die Globals direkt schreiben — normalerweise für Geschwindigkeit oder weil der Code der SQL-Projektion vorausgeht — können Werte speichern, die die Klassendefinition als unmöglich bezeichnet.
Nichts bricht zur Schreibzeit. Die Diskrepanz erscheint erst später, wenn ein Treiber den Wert liest und ihn mit den Metadaten in Einklang bringen muss, die die Klassendefinition ankündigt. Diese Versöhnung kann drei Wege gehen:
- Zugriffsfehler — der Treiber kann den Wert überhaupt nicht lesen und eine Ausnahme wird zur Abfragezeit geworfen.
- Stille Korruption — der Wert wird erfolgreich gelesen, entspricht aber nicht den deklarierten Metadaten. Kein Fehler wird ausgelöst, sodass die Inkonsistenz verborgen bleibt.
- Unentdeckte Mutation — der Wert wird gelesen, sieht korrekt aus und ist nicht das, was gespeichert ist. Der Treiber hat ihn auf dem Weg nach draußen in etwas Typkompatibles gezwungen.
Der erste ist ein Ärgernis. Der zweite und dritte sind die gefährlichen, weil jeder nachgelagerte Konsument, der den Metadaten vertraut — ein ETL-Job, ein Schemagenerator, ein Report, ein Interface-Vertrag — jetzt von einem Versprechen ausgeht, das die Daten nicht halten.
Das Verhalten reproduzieren
Um die Szenarien reproduzierbar statt anekdotisch zu machen, sind sie in die DATATYPE_SAMPLE-Datenbank eingebaut, die auf der InterSystems Open Exchange veröffentlicht ist:
Alle drei Szenarien verwenden eine Tabelle:
CREATE TABLE SQLUser.Employee (
ID BIGINT NOT NULL AUTO_INCREMENT,
Age INTEGER,
Company BIGINT,
DOB DATE,
FavoriteColors VARCHAR(4096),
Name VARCHAR(50) NOT NULL,
Notes LONGVARCHAR,
Picture LONGVARBINARY,
SSN VARCHAR(50) NOT NULL,
Salary INTEGER,
Spouse BIGINT,
Title VARCHAR(50),
Home_City VARCHAR(80),
Home_State VARCHAR(2),
Home_Street VARCHAR(80),
Home_Zip VARCHAR(5),
Office_City VARCHAR(80),
Office_State VARCHAR(2),
Office_Street VARCHAR(80),
Office_Zip VARCHAR(5)
);
Die unten referenzierten Zeilen sind absichtlich durch direkten Global-Zugriff beschädigt, genau so, wie es eine Legacy-Routine tun würde.
Szenario 1: Zugriffsfehler
Die DOB-Spalte ist als DATE deklariert. In der Beispieldatenbank halten die Zeilen mit Primärschlüsseln 101, 180, 181, 182, 183, 184 und 185 Werte, die keine gültigen Daten sind, direkt in das Global geschrieben.
Die meisten Clients antworten mit einer einzigen generischen Konvertierungsausnahme und keinem Hinweis, woher sie kam. SQL DATA LENS meldet den Fehler, die Zeile und Spalte, in der er auftrat, und den Wert, der tatsächlich in der Datenbank gehalten wird. Für die erste betroffene Zeile ist der interne Wert in DOB 39146<Ruined> — ein gültiges Datenseriell mit angehängter Zeichenkette, weshalb die Umwandlung zu DATE fehlschlägt.
Sie können auch entscheiden, wie sich das Result-Set verhalten soll, wenn es auf eine solche Zelle trifft. Standardmäßig stoppt das Lesen beim ersten fehlerhaften Wert; das Ausschalten davon lässt die Abfrage bis zum Abschluss laufen, sodass Sie jede schlechte Zeile in einem Durchgang sammeln können, anstatt sie eine Ausnahme nach der anderen zu beheben. Der Schalter ist auf der Haupt-Toolbar und gilt global.
Symptome
- Eine Konvertierungs- oder Cast-Ausnahme zur Abfragezeit, oft ohne Zeilenreferenz.
- Dieselbe Abfrage funktioniert, wenn die anstößigen Zeilen durch eine
WHERE-Klausel ausgeschlossen werden. - Reports und Exporte schlagen mittendrin mit teilweiser Ausgabe fehl.
Lösungsschritte
- Führen Sie die Abfrage mit auf Fortfahren gesetzter Lesefehlerbehandlung aus, sodass die vollständige Liste der betroffenen Zeilen in einer Ausführung gesammelt wird.
- Notieren Sie die Primärschlüssel und die rohen Werte, die für die fehlschlagenden Zellen gezeigt werden.
- Inspizieren Sie das zugrunde liegende Global mit dem Global Browser, um zu bestätigen, was gespeichert ist und wie es dorthin kam.
- Korrigieren Sie die gespeicherten Werte — entweder zurück zu einer gültigen Darstellung des beabsichtigten Datums oder zu
NULL, wo der ursprüngliche Wert nicht wiederherstellbar ist. - Beheben Sie die Routine, die sie geschrieben hat. Bis das direkte Global-Schreiben durch Validierung geht oder korrigiert wird, werden die Zeilen zurückkommen.
Szenario 2: stille Korruption
Zeile ID = 110 der Employee-Tabelle sieht unauffällig aus. Beim ersten Blick und beim zweiten Blick ist nichts falsch: Jeder Client liest sie, keine Warnung erscheint, und das Gitter zeigt einen vollkommen gewöhnlichen Mitarbeiterdatensatz.
Die Name-Spalte ist als VARCHAR(50) deklariert. Der Wert in dieser Zeile ist 60 Zeichen lang.
Was passiert
- Die meisten Tools lesen den Wert ohne Beschwerde, weil der Treiber nachsichtig mit überlangen Strings auf dem Weg nach draußen ist.
- Keine Warnung, kein Fehler, nichts im Log.
- Die Verletzung ist nur sichtbar, wenn Sie den Wert absichtlich gegen die Metadaten vergleichen.
Warum es wichtig ist
Ob dies schadet, hängt vollständig davon ab, was als Nächstes passiert. Wenn der Wert nur jemals angezeigt wird, bricht nichts. Wenn er eine Schnittstelle überquert, wo die Metadaten als Vertrag behandelt werden, bricht er dort statt hier, und weit entfernt von der Ursache:
- Eine ETL-Zielspalte, die von den Quellmetadaten dimensioniert ist, lehnt die Zeile ab oder schneidet sie ab.
- Eine generierte Klasse, DTO oder Avro-/Parquet-Schema deklariert 50 Zeichen und schlägt beim Schreiben fehl.
- Eine nachgelagerte Datenbank mit strengerer Typ-Überprüfung verweigert das Einfügen.
- Daten werden stillschweigend abgeschnitten, und niemand bemerkt es, bis eine Abstimmung fehlschlägt.
Lösungsschritte
- Generieren Sie aus dem Kontextmenü der Tabelle im Table Viewer das Integritätsprüfungs-SQL für die Tabelle. SQL DATA LENS baut die Prüfungen aus den aktuellen Metadaten, sodass jede Zeichenlängen-, numerische und Datums-Constraint abgedeckt ist, ohne dass Sie Prädikate von Hand schreiben. Dieselbe Generierung funktioniert für Views und gespeicherte Prozeduren.
- Führen Sie die Prüfungen aus und behandeln Sie jede zurückgegebene Zeile als Befund: Es ist ein Wert, der der Deklaration widerspricht.
- Entscheiden Sie für jeden Befund, welche Seite falsch ist. Entweder sind die Daten schlecht und müssen korrigiert werden, oder die Deklaration ist zu eng, und die Klassendefinition sollte erweitert und neu kompiliert werden.
- Führen Sie die Prüfungen nach der Korrektur erneut aus und behalten Sie sie als geplantes Skript im Script Manager, sodass eine Regression vom nächsten Lauf statt von einem nachgelagerten Konsumenten erfasst wird.
Szenario 3: unentdeckte Mutation
Zeile ID = 120 ist die subtile. Weder der Treiber noch der Client meldet ein Problem, und dieses Mal sieht der Wert sogar so aus, als ob er den Metadaten entspricht. Die Spalte ist als INTEGER deklariert, und das Gitter zeigt ordnungsgemäß eine Ganzzahl — 0.
Diese Null ist nicht in der Datenbank. Eine Zeichenkette wurde durch direkten Global-Zugriff in das Feld injiziert, und der Treiber, unfähig, eine Ganzzahl daraus zu machen, produzierte 0 auf dem Weg nach draußen. Das Result-Set ist intern konsistent und völlig falsch.
Was passiert
- Der Treiber zwingt den gespeicherten Wert in etwas, das dem deklarierten Typ entspricht.
- Der Client zeigt einen plausiblen Wert, sodass keine menschliche Überprüfung ihn markiert.
- Nur ein direkter Blick auf das Global enthüllt den echten Inhalt.
Dies ist der Fehlermodus, um den man sich bei Reporting- und Migrationsarbeit sorgen muss. Ein Zugriffsfehler stoppt den Job; eine Mutation lässt ihn mit einer falschen Zahl darin beenden. Eine gezwungene 0 in einer Salary-, Age- oder Mengenspalte wird ohne Beschwerde aggregiert, gemittelt und grafisch dargestellt.
Lösungsschritte
- Generieren und führen Sie die diagnostischen Abfragen für die Tabelle aus. Weil die Prüfungen die gespeicherte Darstellung gegen den deklarierten Typ vergleichen, anstatt durch dieselbe Zwangung zu lesen, markieren sie Werte, die das gewöhnliche
SELECTals gültig meldet. - Öffnen Sie den betroffenen Knoten im Global Browser und lesen Sie den rohen Subscript-Wert. Dies ist die einzige Ansicht, die den Inhalt ohne Treiberinterpretation zeigt, und es ist, wo die Zeichenkette in Zeile 120 sichtbar wird.
- Verwenden Sie den Data Inspector auf der Zelle, wo der Wert strukturiert sein könnte —
$LISTBUILD, JSON, XML oder binär — um zu sehen, wie er kodiert ist, anstatt wie er rendert. - Korrigieren Sie den gespeicherten Wert, dann führen Sie jedes Aggregat erneut aus, das die Spalte berührte. Ein mutierter Wert betrifft nicht nur seine eigene Zeile; er wurde bereits in jede Summe eingerollt, die seit dem Schreiben berechnet wurde.
Eine praktische Routine
Metadaten-Drift ist kein einmaliges Ereignis, also lohnt es sich, es wie jede andere Datenqualitätsprüfung zu behandeln, anstatt als Vorfall:
- Generieren Sie Integritätsprüfungen für die Tabellen, Views und gespeicherten Prozeduren im Namespace und behalten Sie die Skripte unter Versionskontrolle.
- Führen Sie sie nach jeder Migration, jedem Datenladen oder Upgrade und nach jeder Änderung an Code aus, der Globals direkt schreibt.
- Lassen Sie die Lesefehlerbehandlung während der Untersuchung auf Fortfahren gesetzt, sodass ein Durchgang das vollständige Bild produziert.
- Wenn sich ein Befund als legitim erweitertes Feld herausstellt, beheben Sie die Klassendefinition anstatt der Prüfung.
Die drei Szenarien oben sind alle mit der DATATYPE_SAMPLE-Datenbank reproduzierbar, also lohnt es sich, sie zu installieren und sie einmal gegen Ihre eigene Treiberversion durchzugehen, bevor Sie ihnen in der Produktion begegnen. Wenn Sie das Tool noch nicht installiert haben, beginnen Sie auf der Download-Seite; das Benutzerhandbuch deckt die hier referenzierten SQL-Editor-Optionen im Detail ab.