أنا أتخيل فقط، لكن إليك نظريتي غير المؤكدة:
شغلت عملية إعادة الفهرسة مرتين في وقت واحد (أي ccnew ثم ccnew1)
وفي كلتا الحالتين ظهرت أخطاء.
ربما عندما تفشل العملية، لا تقوم بإعادة التراجع، بل تترك المخلفات ثم تتوقف.
أنا أتخيل فقط، لكن إليك نظريتي غير المؤكدة:
شغلت عملية إعادة الفهرسة مرتين في وقت واحد (أي ccnew ثم ccnew1)
وفي كلتا الحالتين ظهرت أخطاء.
ربما عندما تفشل العملية، لا تقوم بإعادة التراجع، بل تترك المخلفات ثم تتوقف.
يبدو هذا الأمر محتملاً للغاية جدًا جدًا.
أود فقط إضافة رأيي هنا،
لا يمكن إسقاط مؤشرات Toast بهذه الطريقة،
كان علي أن أفعل:
su postgres
psql
\connect discourse
drop index pg_toast.pg_toast_309322_index_ccnew;
drop index pg_toast.pg_toast_309322_index_ccnew1;
ما ورد أعلاه ينطبق فقط على pg toast لأن مستخدم discourse ليس لديه صلاحية الوصول إلى هذا المؤشر.
PG::InsufficientPrivilege: ERROR: permission denied for schema pg_toast
إسقاط مؤشرات التوست أمر مخيف للغاية. أظن أنه لا خيار آخر لديك هنا. نعم، يجب عليك القيام بذلك من psql.
وها يأتي إعادة الفهرسة السعيدة:
discourse=# REINDEX SCHEMA CONCURRENTLY public;
REINDEX
![]()
ممتاز! عثرت على جميع الفهارس التي تحتوي على “ccnew” في اسمها عبر هذا الاستعلام.
psql
\connect discourse
select tablename,indexname,indexdef from pg_indexes where indexname LIKE '%ccnew%';
incoming_referer.csv (7.2 KB)
اتضح أن لدي 30 فهرسًا من هذا القبيل، وجميعها في جدول incoming_referers. لذا تحققت من أن جميع فهارس ccnew كانت بالفعل نسخًا مكررة عبر عمود indexdef في هذا الاستعلام.
select indexname,indexdef from pg_indexes where tablename = 'incoming_referers';
ccnew.csv (6.6 KB)
ثم قمت بحذفها جميعًا بنجاح.
DROP INDEX incoming_referers_pkey_ccnew;
DROP INDEX incoming_referers_pkey_ccnew_ccnew;
DROP INDEX incoming_referers_pkey_ccnew1;
...وهكذا لجميع الـ 30
عندها أعيدت فهرسة المخطط بالكامل مرة أخرى، لكن لم يتم إعادة بناء فهارس ccnew المتطابقة لجدول incoming_referers مرة أخرى، كما تم العثور على ثلاثة فهارس pg_toast. قمت بحذفها ثم أعيدت فهرسة المخطط بالكامل مرة أخرى، وحصلت على أخطاء أكثر، وعثرت على المزيد من فهارس ccnew في مخطط discourse، ثم أعيدت الفهرسة للمرة الثالثة…
لا يمكنني إكمال إعادة فهرسة كاملة دون أخطاء؛ حيث تستمر في إنشاء فهارس ccnew جديدة ثم تفشل في إعادة بنائها في كل مرة. بعد 4 عمليات إعادة بناء كاملة، قمت بحذف فهارس ccnew ثم استسلمت. أعتقد أنه يمكنني محاولة إعادة البناء بدون استخدام خيار concurrently، لكن ذلك سيسبب توقفًا في الخدمة لفترة طويلة.
على أي حال، أعتقد أن معظم المستخدمين الذين قاموا بالترقية من PG10 إلى PG12 وحاولوا إعادة الفهرسة لاحقًا يمتلكون هذه الفهارس الإضافية ccnew، ويجب حذفها جميعًا. فستستهلك مساحة فقط وتزيد من عمليات كتابة القرص I/O دون أي فائدة.
نفذت ما يعادله في Data-Explorer. كان أسهل قليلاً في الإدارة.
ما فعلته هو أنني أخذت جميع فهارس ccnew/ccnew1/ccnew2…ccnewn، وحذفتها تمامًا ثم أعيدت الفهرسة. وهذا ما أصلح المشكلة بالنسبة لي.
ccnew هي ميزة في postgres لوضع علامات على الفهارس، وأعتقد أن هناك بعض عدم الكفاءة في العملية تتسبب في بقاء هذه الفهارس إذا فشلت عملية الفهرسة لسبب ما.
لا يمكنني إلا أن أقترح عليك العمل أولاً على السبب الجذري للمشكلة. كان لدي وسوم مكررة اضطررت إلى حذفها قبل المتابعة في حذف الفهارس. فلو بقيت حتى علامة مكررة واحدة، فلن يتم الفهرسة بشكل صحيح وسيتم إنشاء فهرس ccnew'n' آخر وفشله.
أنت محق، لا يزال لدي تكرارات — لا يمكن إعادة بناء فهارس غير ccnew بشكل غير متزامن. أحتاج إلى إزالة هذه الصفوف المكررة.
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.
المثير للغرابة حقًا هو أنني أرى صفًا واحدًا فقط مع كل من قيم incoming_domain_id تلك في incoming_referer. إذن لماذا هي مكررة؟
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 أو @riking، هل يجب أن أحذف هذين الصفين على النحو التالي:
DELETE FROM incoming_referers WHERE path='/search/' AND incoming_domain_id IN (1861,3433);
… أعتقد أنني أتعلم postgres في النهاية، هه.
لا، سيؤدي ذلك إلى حذف كليهما — بل تريد استخدام WHERE للعثور على معرفي id، ثم اختيار معرف id واحد فقط لحذفه.
استعلامك يستخدم الفهرس التالف، وهذا هو السبب في ظهور صف واحد فقط لكل منهما. جرّب ما يلي:
... where path LIKE '%/search/' ...
حسناً، هذا يعيد 43 صفًا.
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)
إذن، هل يجب أن أنفذ الأمر التالي؟
DELETE FROM incoming_referers WHERE path LIKE '%/search/' AND id IN (42845,43350,42849);
نعم، يبدو أمر DELETE صحيحًا ويجب أن يسمح لك بأخذ نسخة احتياطية نظيفة.
صدق أو لا تصدق، فشل أكثر. في المجموعة الأولى، اكتشفت مفتاحًا مكررًا آخر في /m/search لم يتم التقاطه بواسطة الويلدكارد %/search/ لسبب ما، فحذفته. قمت بإعادة الفهرسة مرة أخرى (كل مرة تستغرق ساعة تقريبًا!) وظهور المزيد من الأخطاء يشير إلى مفتاح مكرر في users(username_lower).
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.
لكن الحقيقة هي، كانت هناك صف واحد فقط يحتوي على username_lower=john_smith! حان وقت ارتداء قبعة المحقق.
عند النظر إلى واجهة إدارة المنتدى، كان لدينا مستخدمان منفصلان يُدعى كل منهما “john_smith” و"John_Smith"-- لاحظ اختلاف الأحرف الكبيرة والصغيرة. لذا قمت بحذف المستخدم الذي يحتوي على أحرف صغيرة فقط على مستوى المنتدى لأنه لم يكن نشطًا منذ 4 سنوات، ثم تم إعادة بناء هذا الفهرس بنجاح.
شغلت عملية إعادة بناء كاملة أخرى، حيث استغرقت كل منها ساعة تقريبًا، وأخيرًا أعتقد أننا بخير-- خطأ واحد فقط، لكن لا توجد تكرارات، فقط pg_toast ccnew. قمت بإسقاطه.
discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING: cannot reindex invalid index "pg_toast.pg_toast_2783329_index_ccnew" concurrently, skipping
REINDEX
لقد كانت رحلة.
هل يمكن/سيتم أتمتة إصلاحات قاعدة البيانات هذه في ترقية مستقبلية لـ Discourse؟
من المرجح أن تتوقف فساد فهرس PostgreSQL في ترقية مستقبلية، إذا تمكن بيتر من الحصول على تكرار متسق.
إذا فشل إعادة الفهرسة المتزامن (REINDEX) لأن الجدول يحتوي على بيانات غير صالحة، فيجب عليك:
إصلاح البيانات غير الصالحة، كما تم ذلك هنا.
سرد الفهارس غير الصالحة باستخدام الأمر SELECT pg_class.relname FROM pg_class, pg_index WHERE pg_index.indisvalid = false AND pg_index.indexrelid = pg_class.oid;
حذف كل فهرس غير صالح مدرج أعلاه باستخدام الأمر DROP INDEX <indexname>;
حاول تنفيذ الأمر REINDEX مرة أخرى.
بعد تشغيل الترقية إلى 2.5.0beta5 واتباع الإرشادات ما بعد التحديث لإعادة فهرسة قاعدة البيانات، حصلت على هذا:
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.
أفضل عدم تجربة ذلك… إذن، كيف يمكنني حذف التكرار بأمان؟
لا، الترقية لا تتسبب في تلف الفهرس، بل إنها فقط توضح أن الفهرس تالف بالفعل. يمكنك التحقق من ذلك بمحاولة استعادة نسخة احتياطية من بياناتك على خادم آخر (حتى لو كان يعمل بإصدار pg10). أو حاول إعادة بناء الفهرس على التثبيت الحالي لديك. غير واضح ما الذي يسبب تلف الفهارس، لكن هناك أمل في أن يكون إصدار pg12 أقل عرضة لحدوث هذه المشكلة.
هناك بعض الفوائد في الأداء من الترقية، لكن تأجيلها ليس فكرة سيئة.
الآن أصبح الأمر متأخرًا، لذا لا أزال أبحث عن توجيهات بشأن الخطوات التالية.
شيء مثل
select id, plugin_name, key from plugin_store_rows where plugin_name like '%discourse-data-explorer%'
يجب أن يعطيك الصفوف. أعتقد أنه من الآمن بما يكفي حذفها.
أعتقد أن ilike ستكون مطلوبة