Обмеження зовнішнього ключа

В даний час InnoDB - основна підсистема зберігання для MySQL, підтримує зовнішні ключі, так що у тих, кому вони необхідні, вибір обмежений 1. Компанія MySQL AB обіцяла, що коли-небудь сервер самостійно буде підтримувати зовнішні ключі способом, не залежною від підсистеми зберігання , але в доступному для огляду майбутньому InnoDB залишається єдиною з основних підсистем, в яких ця функція реалізована. Тому її ми і будемо розглядати.

Зовнішні ключі обходяться не дарма. Як правило, їх наявність означає, що сервер повинен заглядати в іншу таблицю при кожній зміні певних даних. Хоча для прискорення операції InnoDB примусово будує індекс, це зовсім не усуває всі негативні наслідки подібних перевірок. При цьому може навіть вийти дуже великий індекс, який має вкрай низьку селективність. Припустимо, наприклад, що у величезній таблиці є стовпець status, і потрібно, щоб він міг утримувати тільки коректні значення, а таких усього три. Необхідний для цього додатковий індекс помітно збільшить загальний розмір таблиці - навіть якщо розмір самого стовпчика малий і, особливо, якщо велика довжина первинного ключа; при цьому сам індекс не потрібен ні для чого, крім перевірки зовнішнього ключа.

І все ж в деяких випадках зовнішні ключі можуть підвищити продуктивність. Якщо життєво необхідно гарантувати, що дані в двох взаємопов'язаних таблицях несуперечливі, то ефективніше доручити перевірку сервера, а не займатися цим на рівні додатку. Зовнішні ключі корисні також для каскадного видалення та оновлення, хоча ці операції виконуються через підрядник, тобто повільніше, ніж запит з оновленням декількох таблиць або пакетна операція.

Через зовнішніх ключів запит може «поширюватися» на інші таблиці, а це означає захоплення блокувань. Наприклад, при спробі вставити рядок в підпорядковану таблицю, обмеження зовнішнього ключа примусить InnoDB перевірити наявність відповідного значення в головній таблиці. При цьому необхідно встановити блокування на рядок головною таблиці, щоб її ніхто не видалив до завершення транзакції. Це може привести до несподіваного очікуванню блокування і навіть до взаімоблокіровка на таблицях, до яких ви безпосередньо не звертаєтеся. Такого роду проблеми далекі від інтуїтивно очевидних і вирішувати їх дуже важко.

Іноді замість зовнішніх ключів можна використовувати тригери. Для таких операцій, як каскадне оновлення, зовнішні ключі працюють швидше тригерів, але якщо єдине призначення ключа - перевірити обмеження, як в прикладі зі стовпцем status, то, можливо, ефек тивності написати тригер, включивши в нього явний список допустимих значень (а можна просто скористатися типом даних ENUM).

Найчастіше має сенс перевіряти обмеження в додатку, а не використовувати для цієї мети зовнішні ключі.

Схожі статті