حل مشکل زدن ctrl+c در وسط ساخت ایندکس

حل مشکل ایندکس‌های بلاتکلیف در اوراکل (خطای ORA-08104)

تصور کنید در حال ساخت یک ایندکس بزرگ به صورت ONLINE هستید و ناگهان به هر دلیلی (مثل فشردن Ctrl+C، قطع شبکه یا کمبود فضا) عملیات قطع می‌شود. حالا شما با وضعیتی مواجه می‌شوید که نه می‌توانید ایندکس را بسازید و نه می‌توانید آن را حذف کنید! در این مقاله به بررسی این مشکل و نحوه حل آن می‌پردازیم.

۱. نشانه‌های بروز مشکل

در این حالت، اوراکل دچار یک تناقض در "دیتادیکشنری" می‌شود. وقتی می‌خواهید دستورات مختلف را اجرا کنید، با پاسخ‌های متناقضی روبرو می‌شوید:

  • هنگام ساخت مجدد: می‌گوید این نام قبلاً استفاده شده است (ORA-00955).
  • هنگام حذف (Drop): می‌گوید چنین ایندکسی وجود ندارد (ORA-01418).
  • هنگام تغییر یا بازسازی: با خطای زیر روبرو می‌شوید که نشان می‌دهد ایندکس در وضعیت "در حال ساخت" مانده است:
sys@searchcd(135)> ALTER INDEX SEARCH_ENG.IX_GOODS_REL_PRICE_ID rebuild;
ERROR at line 1:
ORA-08104: this index object 91565 is being online built or rebuilt

۲. چرا این اتفاق می‌افتد؟

وقتی ایندکسی را به صورت آنلاین می‌سازید، اوراکل چندین شیء موقت ایجاد می‌کند تا اجازه دهد کاربران همزمان با ساخت ایندکس، داده‌ها را تغییر دهند. اگر عملیات قطع شود، این اشیاء در جداول سیستمی (مثل OBJ$) باقی می‌مانند اما در نماهای مدیریتی مثل DBA_INDEXES دیده نمی‌شوند.

نقش SMON: در حالت عادی، وظیفه پاک‌سازی این اشیاء معلق بر عهده فرآیند SMON است. SMON به صورت دوره‌ای (که ممکن است حدود یک ساعت یا بیشتر طول بکشد) این موارد را بررسی و پاک می‌کند. اما در محیط‌های عملیاتی، ما معمولاً نمی‌توانیم یک ساعت منتظر بمانیم تا SMON کارش را انجام دهد.

۳. راه حل سریع: استفاده از DBMS_REPAIR

بهترین و امن‌ترین راه برای حذف این "ایندکس‌های شبح"، استفاده از پکیج DBMS_REPAIR است. مراحل زیر را دنبال کنید:

مرحله اول: پیدا کردن شناسه شیء (Object ID)

ابتدا از جدول دیتادیکشنری OBJ$، شماره شناسایی (OBJ#) ایندکس را پیدا می‌کنیم:

sys@searchcd(135)> select obj# ,name from obj$ where OBJ#=91565;

      OBJ# NAME
---------- -------------------------------------------------------
     91565 IX_GOODS_REL_PRICE_ID

مرحله دوم: پاک‌سازی دستی

حالا با استفاده از تابع online_index_clean، به اوراکل دستور می‌دهیم که تمام متعلقات این ایندکس نیمه‌کاره را فوراً پاک کند:

 declare
  lv_ret BOOLEAN;
begin
  lv_ret := dbms_repair.online_index_clean(91565);
end;
/

مرحله سوم: تایید و ساخت مجدد

بعد از اجرای دستور بالا، اگر دوباره جستجو کنید، می‌بینید که رکورد پاک شده است و حالا می‌توانید بدون مشکل ایندکس خود را بسازید:

sys@searchcd(135)> select obj# ,name from obj$ where OBJ#=91565;
no rows selected

sys@searchcd(135)> CREATE INDEX SEARCH_ENG.IX_GOODS_REL_PRICE_ID ON SEARCH_ENG.T_GOODS
  2  (RELEVANCE_SCORE DESC, PRICE DESC, ID)
  3  parallel 8 tablespace SEARCH_ENG;

Index created.

۴. چه زمان‌های دیگری این مشکل پیش می‌آید؟

علاوه بر قطع دستی با Ctrl+C، موارد زیر هم می‌توانند منجر به این وضعیت شوند:

  • قطع اتصال شبکه: اگر ارتباط کلاینت با سرور قطع شود و سشن در دیتابیس Kill شود.
  • پر شدن فضای Temp: اگر در حین مرتب‌سازی داده‌ها، فضای Tablespace موقت تمام شود.
  • خطاهای موازی (Parallel): بروز خطا در یکی از اسلیوهای موازی در دستوراتی که با parallel اجرا می‌شوند.
  • Instance Crash: خاموش شدن ناگهانی دیتابیس در حین انجام عملیات DDL آنلاین.