sql >> Databáze >  >> RDS >> Mysql

Omezení cizího klíče:Kdy použít ON UPDATE a ON DELETE

Neváhejte dát databázi omezení. Budete mít jistotu, že budete mít konzistentní databázi, a to je jeden z dobrých důvodů, proč databázi používat. Zvláště pokud to požaduje několik aplikací (nebo pouze jedna aplikace, ale s přímým režimem a dávkovým režimem využívajícím různé zdroje).

S MySQL nemáte pokročilá omezení, jako byste měli v postgreSQL, ale alespoň omezení cizích klíčů jsou docela pokročilá.

Vezmeme si příklad, firemní tabulku s uživatelskou tabulkou obsahující lidi z diplomové firmy

CREATE TABLE COMPANY (
     company_id INT NOT NULL,
     company_name VARCHAR(50),
     PRIMARY KEY (company_id)
) ENGINE=INNODB;

CREATE TABLE USER (
     user_id INT, 
     user_name VARCHAR(50), 
     company_id INT,
     INDEX company_id_idx (company_id),
     FOREIGN KEY (company_id) REFERENCES COMPANY (company_id) ON...
) ENGINE=INNODB;

Podívejme se na AKTUALIZACI klauzule:

  • NA OMEZENÍ AKTUALIZACÍ :výchozí :pokud se pokusíte aktualizovat company_id v tabulce COMPANY, engine operaci odmítne, pokud na tuto společnost odkazuje alespoň jeden UŽIVATEL.
  • PO AKTUALIZACI ŽÁDNÁ AKCE :stejné jako OMEZIT.
  • V KASKÁDĚ AKTUALIZACE :obvykle ten nejlepší :pokud aktualizujete company_id v řádku tabulky COMPANY, engine jej aktualizuje odpovídajícím způsobem na všech řádcích USER odkazujících na tuto SPOLEČNOST (ale v tabulce USER nejsou aktivovány žádné spouštěče, varování). Motor bude změny sledovat za vás, je to dobré.
  • ON UPDATE SET NULL :pokud aktualizujete company_id v řádku tabulky COMPANY, modul nastaví související USER company_id na NULL (mělo by být dostupné v poli USER company_id). V aktualizaci nevidím žádnou zajímavou věc, která by s tím měla co do činění, ale mohu se mýlit.

A nyní na ON DELETE strana:

  • ON OMEZENÍ SMAZÁNÍ :výchozí :pokud se pokusíte smazat ID_společnosti v tabulce SPOLEČNOST, engine operaci odmítne, pokud na tuto společnost odkazuje alespoň jeden UŽIVATEL, což vám může zachránit život.
  • NA SMAZÁNÍ ŽÁDNÁ AKCE :stejné jako OMEZIT
  • NA DELETE CASCADE :nebezpečné :pokud smažete řádek společnosti v tabulce SPOLEČNOST, engine smaže i související USER. To je nebezpečné, ale lze to použít k automatickému čištění sekundárních tabulek (takže to může být něco, co chcete, ale zcela jistě ne pro příklad SPOLEČNOSTI<->UŽIVATELE)
  • ON DELETE SET NULL :hrst :pokud smažete řádek SPOLEČNOSTI, související UŽIVATELÉ budou mít automaticky vztah k NULL. Pokud je pro uživatele bez společnosti vaše hodnota Null, může to být dobré chování, například možná potřebujete ponechat uživatele ve své aplikaci jako autory nějakého obsahu, ale odstranění společnosti pro vás není problém.

obvykle moje výchozí nastavení je:ON DELETE RESTRICT ON UPDATE CASCADE . s některými ON DELETE CASCADE pro tabulky sledování (protokoly--ne všechny protokoly--, podobné věci) a ON DELETE SET NULL když hlavní tabulka je 'jednoduchý atribut' pro tabulku obsahující cizí klíč, jako tabulka JOB pro tabulku USER.

Upravit

Už je to dlouho, co jsem to napsal. Nyní si myslím, že bych měl přidat jedno důležité varování. MySQL má jedno velké zdokumentované omezení s kaskádami. Kaskády nespouštějí spouštěče . Takže pokud jste si byli v tomto enginu dostatečně jisti, abyste mohli používat spouštěče, měli byste se vyhnout kaskádovým omezením.

==> Viz níže poslední úprava, věci se v této doméně hýbou

A nemyslím si, že se to jednoho dne napraví. Omezení cizího klíče jsou spravována úložištěm InnoDb a spouštěče jsou spravovány enginem MySQL SQL. Oba jsou odděleni. Innodb je jediné úložiště se správou omezení, možná jednoho dne přidají spouštěče přímo do úložiště, možná ne.

Ale mám svůj vlastní názor na to, který prvek byste si měli vybrat mezi špatnou implementací triggeru a velmi užitečnou podporou omezení cizích klíčů. A jakmile si zvyknete na konzistenci databáze, zamilujete si PostgreSQL.

12/2017 – Aktualizace této úpravy o MySQL:

jak uvedl @IstiaqueAhmed v komentářích, situace se na toto téma změnila. Sledujte tedy odkaz a ověřte si skutečnou aktuální situaci (která se může v budoucnu opět změnit).



  1. Jak spustit dotaz SQLite asynchronně na vláknu na pozadí?

  2. Import PostgreSQL CSV z příkazového řádku

  3. Zkontrolujte typ parametru funkce oddílu v SQL Server (T-SQL)

  4. OMEZENÍ MySQL a ŽÁDNÁ AKCE