Korrupte Indizes in PG12, wie behebe ich das?

Ich spekuliere nur, aber hier ist meine Theorie mit Aluminiumfolie:

Ich habe Reindex zweimal gleichzeitig ausgeführt (also zuerst ccnew, ccnew1),
und beide Male traten Fehler auf.

Vielleicht wird bei einem Fehler einfach nicht rückgängig gemacht, sondern der Müll bleibt zurück und das Programm beendet sich.

Das klingt sehr, sehr, sehr wahrscheinlich.

Ich möchte hier nur meine zwei Cent einbringen.

Toast-Indizes können auf diese Weise nicht gelöscht werden.
Ich musste folgendes tun:

su postgres
psql
\connect discourse
drop index pg_toast.pg_toast_309322_index_ccnew;
drop index pg_toast.pg_toast_309322_index_ccnew1;

Das obige gilt nur für pg_toast, da der Discourse-Benutzer keinen Zugriff auf diesen Index hat.
PG::InsufficientPrivilege: ERROR: permission denied for schema pg_toast

Toast-Indizes zu löschen ist extrem beängstigend. Ich schätze, du hast hier aber keine andere Wahl. Ja, das musst du über psql machen.

Und hier kommt die fröhliche Neuindizierung:

discourse=# REINDEX SCHEMA CONCURRENTLY public;
REINDEX

:partying_face:

Toll gefunden! Ich habe alle Indizes mit „ccnew

Ich habe das Äquivalent in Data-Explorer ausgeführt. Das war etwas einfacher zu handhaben.

Was ich getan habe, war, alle ccnew/ccnew1/ccnew2…ccnewn-Indizes zu entfernen und den Index neu zu erstellen. Das hat bei mir funktioniert.

ccnew ist eine PostgreSQL-Funktion zum Markieren von Indizes, und ich denke, es ist eine gewisse Ineffizienz im Prozess, die dazu führt, dass diese übrig bleiben, wenn die Indexierung aus irgendeinem Grund fehlschlägt.

Ich kann nur empfehlen, zunächst die Grundursache des Problems zu beheben. Ich hatte doppelte Tags, die ich löschen musste, bevor ich mit dem Entfernen der Indizes fortfahren konnte. Wenn auch nur ein einziges doppeltes Tag übrig bleibt, wird die Indexierung nicht ordnungsgemäß durchgeführt und ein weiterer ccnew'n'-Index erstellt, was zum Fehler führt.

Du hast recht, ich habe immer noch Duplikate – ich kann die nicht-ccnew-Indizes nicht nicht-parallel neu aufbauen. Ich muss diese doppelten Zeilen entfernen.

discourse=# reindex index index_incoming_referers_on_path_and_incoming_domain_id;
ERROR:  could not create unique index "index_incoming_referers_on_path_and_incoming_domain_id"
DETAIL:  Key (path, incoming_domain_id)=(/search/, 3433) is duplicated.
discourse=# reindex index index_incoming_referers_on_path_and_incoming_domain_id;
ERROR:  could not create unique index "index_incoming_referers_on_path_and_incoming_domain_id"
DETAIL:  Key (path, incoming_domain_id)=(/search/, 1861) is duplicated.

Das wirklich Seltsame ist, dass ich in incoming_referers nur eine Zeile mit jedem dieser incoming_domain_id-Werte sehe. Warum sind sie dann dupliziert?

discourse=# select * from incoming_referers where path='/search/' AND incoming_domain_id IN (1861,3433);
  id   |   path   | incoming_domain_id 
-------+----------+--------------------
 42845 | /search/ |               1861
 40763 | /search/ |               3433
(2 rows)

@sam oder @riking, soll ich diese beiden Zeilen wie folgt löschen:

DELETE FROM incoming_referers WHERE path='/search/' AND incoming_domain_id IN (1861,3433);

… Ich lerne anscheinend doch noch PostgreSQL, haha.

Nein, das würde beide löschen – Sie möchten die WHERE-Bedingung verwenden, um die beiden ids zu finden, und nur eine der ids zum Löschen auswählen.

Ihre Abfrage verwendet den beschädigten Index, weshalb Sie nur eine Zeile pro Eintrag sehen. Versuchen Sie Folgendes:

... where path LIKE '%/search/' ...

OK, das ergibt 43 Zeilen.

discourse=# select * from incoming_referers where path LIKE '%/search/' ORDER BY incoming_domain_id;
  id   |    path     | incoming_domain_id 
-------+-------------+--------------------
   878 | /search/    |                 63
 33457 | /do/search/ |                567
  1580 | /search/    |                602
  1888 | /search/    |                663
 42983 | /search/    |               1259
  4896 | /search/    |               1788
 42845 | /search/    |               1861
  5162 | /search/    |               1861
  5176 | /search/    |               1866
 43350 | /search/    |               1905
 17238 | /search/    |               1905
 20689 | /search/    |               1982
  5781 | /hg/search/ |               1987
  8031 | /search/    |               2665
 10325 | /search/    |               3192
 11289 | /search/    |               3414
 40763 | /search/    |               3433
 42849 | /search/    |               3433
 13087 | /search/    |               3895
 13159 | /search/    |               3949
 13802 | /do/search/ |               4051
 14407 | /search/    |               4209
 14507 | /search/    |               4211
 15394 | /search/    |               4230
 15533 | /search/    |               4258
 45274 | /search/    |               5303
 20923 | /search/    |               5400
 21317 | /search/    |               5534
 22928 | /search/    |               5918
 22956 | /search/    |               5926
 37448 | /search/    |               6393
 25094 | /search/    |               6412
 25594 | /search/    |               6547
 39655 | /search/    |               6596
 27371 | /search/    |               6986
 27452 | /a/search/  |               7003
 27623 | /search/    |               7041
 31041 | /search/    |               7767
 36943 | /search/    |               8622
 37381 | /search/    |               8711
 37411 | /search/    |               8716
 40424 | /search/    |               9124
 44451 | /search/    |               9525
(43 rows)

Sollte ich also Folgendes ausführen?

DELETE FROM incoming_referers WHERE path LIKE '%/search/' AND id IN (42845,43350,42849);

Ja, dieser DELETE-Befehl sieht korrekt aus und sollte dir eine saubere Sicherung ermöglichen.

Glauben Sie es oder nicht, noch mehr Fehler. Beim ersten Durchlauf habe ich einen weiteren doppelten Schlüssel auf /m/search gefunden, der aus irgendeinem Grund vom %/search/-Wildcards nicht erkannt wurde, und diesen gelöscht. Ich habe erneut indiziert (jedes Mal dauerte es fast eine Stunde!), und es traten weitere Fehler auf, die einen doppelten Schlüssel auf users(username_lower) anzeigten.

discourse=# reindex index index_users_on_username_lower;              
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(john_smith) is duplicated.

Aber das Besondere ist: Es gab nur eine Zeile mit username_lower=john_smith! Zeit für den Detektivhut.

Beim Blick auf die Forum-Admin-Oberfläche stellten wir fest, dass es zwei separate Benutzer mit den Namen „john_smith

Können/werden diese Datenbankkorrekturen in einem zukünftigen Discourse-Upgrade automatisiert werden?

Es ist wahrscheinlicher, dass die PostgreSQL-Indexkorruption bei einem zukünftigen PostgreSQL-Upgrade aufhört, falls Peter eine konsistente Reproduktion erhält.

Wenn ein paralleler REINDEX aufgrund ungültiger Daten in der Tabelle fehlschlägt, müssen Sie Folgendes tun:

  1. Die ungültigen Daten beheben, wie es hier geschehen ist.

  2. Die ungültigen Indizes mit folgender Abfrage auflisten: SELECT pg_class.relname FROM pg_class, pg_index WHERE pg_index.indisvalid = false AND pg_index.indexrelid = pg_class.oid;

  3. Jeden der oben aufgeführten ungültigen Indizes mit DROP INDEX <indexname>; löschen.

  4. Den REINDEX erneut versuchen.

Nach dem Upgrade auf 2.5.0beta5 und der Befolgung der Anweisungen nach dem Update zum Neuindizieren der Datenbank erhalte ich Folgendes:

discourse=# REINDEX SCHEMA CONCURRENTLY public;
ERROR:  could not create unique index "index_plugin_store_rows_on_plugin_name_and_key_ccnew"
DETAIL:  Key (plugin_name, key)=(discourse-data-explorer, q:-10) is duplicated.

Ich möchte hier lieber nicht experimentieren… wie kann ich die Duplikate sicher löschen?

Nein. Das Upgrade beschädigt Ihren Index nicht, es zeigt lediglich an, dass Ihr Index beschädigt ist. Sie können dies überprüfen, indem Sie versuchen, Ihr Backup auf einem anderen Server wiederherzustellen (auch auf einem, auf dem pg10 läuft). Oder versuchen Sie, Ihren Index auf Ihrer bestehenden Installation neu zu erstellen. Es ist unklar, was die beschädigten Indizes verursacht, aber es besteht die Hoffnung, dass dies bei pg12 weniger wahrscheinlich ist.

Es gibt einige Leistungsverbesserungen durch das Upgrade, aber es ist keine schlechte Idee, damit zu warten.

Jetzt ist es zu spät, also suche ich weiterhin nach Orientierung für die nächsten Schritte.

Etwas wie

select id, plugin_name, key from plugin_store_rows where plugin_name like '%discourse-data-explorer%'

sollte die Zeilen zurückgeben. Ich denke, es ist sicher genug, sie zu löschen.

Ich denke, ilike wäre erforderlich.