Удаление внешнего ключа

Запросы, планы, оптимизация запросов, ...

Модераторы: kdv, CyberMax

Ответить
Prog
Сообщения: 12
Зарегистрирован: 15 июл 2009, 11:01

Удаление внешнего ключа

Сообщение Prog » 15 июл 2009, 11:58

В базе (Interbase 7.5) есть таблица с FK, содержащим ссылку на словарь:

Код: Выделить всё

CREATE TABLE CEVENTS (
    CEID         INTEGER NOT NULL,
    ETID         INTEGER,
    CEDATE       TIMESTAMP DEFAULT Current_Timestamp
);

ALTER TABLE CEVENTS ADD CONSTRAINT FK_CE_ETYPES FOREIGN KEY (ETID) REFERENCES ETYPES (ETID) ON DELETE CASCADE ON UPDATE CASCADE;

CREATE TABLE ETYPES (
    ETID      INTEGER NOT NULL,
    ETNAME    VARCHAR(100)
);
Вся работа с таблицей происходит через процедуры, где есть явная проверка корректности значения в этом поле. Т.о. сам constraint нужно удалить, чтобы не напрягать базу неэффективным индексом. Но сделать это не удаётся:

Код: Выделить всё

ALTER TABLE CEVENTS DROP CONSTRAINT FK_CE_ETYPES
This operation is not defined for system tables.
unsuccessful metadata update.
object INDEX is in use .
За полем ETID числится индекс RDB$FOREIGN42:

Код: Выделить всё

alter index RDB$FOREIGN42 inactive
This operation is not defined for system tables.
unsuccessful metadata update.
MODIFY RDB$INDICESS failed.
action cancelled by trigger (3) to preserve data integrity.
Cannot deactivate primary index.

Код: Выделить всё

drop index RDB$FOREIGN42
This operation is not defined for system tables.
unsuccessful metadata update.
ERASE RDB$INDICES failed.
action cancelled by trigger (1) to preserve data integrity.
Cannot delete index used by an Integrity Constraint.
В зависимостях у поля ETID кроме процедур ничего нет, но поиск по системным таблицам выдаёт триггеры:

Код: Выделить всё

select RDB$CONSTRAINT_NAME, RDB$TRIGGER_NAME from RDB$CHECK_CONSTRAINTS
where RDB$CONSTRAINT_NAME = 'FK_CE_ETYPES'
RDB$CONSTRAINT_NAME RDB$TRIGGER_NAME
FK_CE_ETYPES CHECK_47
FK_CE_ETYPES CHECK_48
Однако, таких триггеров в RDB$TRIGGERS нет:

Код: Выделить всё

DROP TRIGGER CHECK_47
This operation is not defined for system tables.
unsuccessful metadata update.
Trigger not found.
Удалить записи из RDB$CHECK_CONSTRAINTS также не удаётся: защита целостности и всё такое.

Т.е. удалить FK нельзя, т.к. к нему привязан индекс, а индекс нельзя трогать, потому что он используется для FK. И ещё эти несуществующие триггеры.. Можно тут что-то сделать, чтобы вычистить всё лишнее из базы?

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Re: Удаление внешнего ключа

Сообщение Dimitry Sibiryakov » 15 июл 2009, 12:17

Удаляй ключ из одиночного подключения через isql.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Удаление внешнего ключа

Сообщение kdv » 15 июл 2009, 15:04

добавлю, что "лишнего" в базе ничего нет. Будешь пытаться "вычистить" - убъешь базу.
Удаление FK по крайней мере до Firebird 2.5 требует делать это в монопольном подключении, т.е. сообщение index in use указывало, что индекс по ФК в данный момент используется (через обращение к таблице), и поэтому ФК удален быть не может.

Prog
Сообщения: 12
Зарегистрирован: 15 июл 2009, 11:01

Re: Удаление внешнего ключа

Сообщение Prog » 15 июл 2009, 17:43

Спасибо, попробую выбрать время для монопольных экспериментов.
kdv писал(а):добавлю, что "лишнего" в базе ничего нет.
Ну а что такое записи о несуществующих триггерах CHECK_47 и CHECK_48? Возможно, это результат чьих-то действий (штатных или с системными таблицами), но теперь-то они точно не нужны.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Удаление внешнего ключа

Сообщение kdv » 15 июл 2009, 22:47

Ну а что такое записи о несуществующих триггерах CHECK_47 и CHECK_48?
это системные триггеры на обновление и удаление, потому что констрейнт FK был создан как

Код: Выделить всё

ON DELETE CASCADE ON UPDATE CASCADE;
надо сказать, что каскадное удаление - зло, а каскадное обновление - еще большее зло. Потому что первичный ключ обычно не модифицируют, ибо он суррогатный (абстрактный), а удаление записей - также зло, т.к. например нельзя удалять клиента, делавшего заказы, иначе вся "бухгалтерия" "поедет" при удалении клиента. Подробнее на эту тему - в поиск.

Prog
Сообщения: 12
Зарегистрирован: 15 июл 2009, 11:01

Re: Удаление внешнего ключа

Сообщение Prog » 16 июл 2009, 10:35

kdv писал(а):это системные триггеры на обновление и удаление
Это бывшие системные триггеры: теперь-то их в RDB$TRIGGERS нету.

Про злокозненность каскадных операций знаю, поэтому и хочется от них избавиться.

Prog
Сообщения: 12
Зарегистрирован: 15 июл 2009, 11:01

Re: Удаление внешнего ключа

Сообщение Prog » 16 июл 2009, 10:45

Хм, получилось удалить FK, создав новый индекс (более эффективный: ETID, CEDATE) и прописав во всех тридцати зависимых процедурах план для его явного использования (по-дефолту почему-то использовался "плохой" индекс, несмотря на никакую статистику).Вчера это сразу не сработало, а сегодня получилось, даже не отключая многопользовательской режим! То ли нагрузка поменьше и никто не успел вредный запрос послать, то ли метаданные прочухались.. Так что спасибо за советы.

Кстати, небольшой оффтоп про то же: использование индекса процедурами где-то фиксируется (в BLR? в кеше?), или выбирается на-лету при каждом запросе?

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: Удаление внешнего ключа

Сообщение kdv » 16 июл 2009, 11:27

Это бывшие системные триггеры: теперь-то их в RDB$TRIGGERS нету.
у тебя, похоже, зависимости окривели. Или ты не туда в системных таблицах смотришь.
создав новый индекс (более эффективный: ETID, CEDATE)
что, поиск постоянно идет по ETID + CEDATE ?
FK убил, теперь контролировать целостность некому?
и прописав во всех тридцати зависимых процедурах план для его явного использования
это звездец, конечно... "там обрыв, но вам туда можно".
использование индекса процедурами где-то фиксируется (в BLR? в кеше?), или выбирается на-лету при каждом запросе?
http://www.ibase.ru/devinfo/ibmyths.htm пункт 9.

Prog
Сообщения: 12
Зарегистрирован: 15 июл 2009, 11:01

Re: Удаление внешнего ключа

Сообщение Prog » 16 июл 2009, 12:23

kdv писал(а):
Это бывшие системные триггеры: теперь-то их в RDB$TRIGGERS нету.
у тебя, похоже, зависимости окривели. Или ты не туда в системных таблицах смотришь.
Ну да, из-за этого и полез спрашивать до того, как всё перепробовал: слишком уж странная ситуация.
Но теперь, при штатном удалении FK записи с упоминанием левых триггеров из RDB$CHECK_CONSTRAINTS также удалились. Так что в этом месте всё поправилось.
что, поиск постоянно идет по ETID + CEDATE ?
Чаще всего по обоим, либо по ETID (и другим полям). Насколько я понимаю, составной индекс выбирает записи по первому полю не хуже, чем отдельный.
FK убил, теперь контролировать целостность некому?
Да её и не надо было контролировать: удалять зависимые PK некому. Но на всякий случай в процедурах стоит проверка, чтобы не добавилось ничего неправильного.
и прописав во всех тридцати зависимых процедурах план для его явного использования
это звездец, конечно... "там обрыв, но вам туда можно".
Да нет там обрыва, просто мостик новый, а чтобы по старому не ездили по-памяти, везде указатели расставлены :)
Теперь, когда дефолтные планы правильные, всё обратно поменял.
использование индекса процедурами где-то фиксируется (в BLR? в кеше?), или выбирается на-лету при каждом запросе?
http://www.ibase.ru/devinfo/ibmyths.htm пункт 9.
Спасибо. Читал ведь когда-то, но никогда бы не догадался там это искать ;)

Ответить