sql >> Databáze >  >> RDS >> Oracle

Ovlivní aktualizace SQL jeho poddotaz během běhu aktualizace?

** Upraveno **

Výběr z cílové tabulky

Od 13.2.9.8. Dílčí dotazy v klauzuli FROM:

Poddotazy v klauzuli FROM mohou vrátit skalární, sloupec, řádek nebo tabulku. Poddotazy v klauzuli FROM nemohou být korelované poddotazy, pokud nejsou použity v klauzuli ON operace JOIN.

Takže ano, můžete provést výše uvedený dotaz.

Problém

Problémy jsou zde skutečně dva. Existuje souběžnost, neboli zajištění, že nikdo jiný nezmění data zpod našich nohou. To je řešeno uzamykáním. Vypořádání se se skutečnou úpravou nových versus starých hodnot je řešeno pomocí odvozených tabulek.

Zamykání

V případě vašeho dotazu výše, s InnoDB, MySQL nejprve provede SELECT a získá zámek pro čtení (sdílený) na každém řádku v tabulce jednotlivě. Pokud byste měli v příkazu SELECT klauzuli WHERE, pak by byly uzamčeny pouze záznamy, které vyberete, kde rozsahy způsobí uzamčení i případných mezer.

Zámek čtení zabraňuje jakémukoli jinému dotazu získat zámky zápisu, takže záznamy nelze aktualizovat odjinud, když jsou uzamčeny pro čtení.

Poté MySQL získá (výhradní) zámek pro zápis na každý záznam v tabulce samostatně. Pokud byste měli ve svém příkazu UPDATE klauzuli WHERE, pak by byly uzamčeny pouze konkrétní záznamy a pokud by klauzule WHERE vybrala rozsah, měli byste rozsah uzamčen.

Jakýkoli záznam, který měl zámek pro čtení z předchozího SELECT, bude automaticky eskalován na zámek zápisu.

Zámek zápisu zabraňuje jiným dotazům získat zámek pro čtení nebo zápis.

Můžete použít Innotop, abyste to viděli tak, že jej spustíte v režimu Lock, spustíte transakci, provedete dotaz (ale nepotvrdíte jej) a uvidíte zámky v Innotopu. Také můžete zobrazit podrobnosti bez Innotop pomocí SHOW ENGINE INNODB STATUS .

Zablokování

Váš dotaz je zranitelný vůči uváznutí, pokud byly spuštěny dvě instance současně. Pokud dotaz A získal zámky čtení, pak dotaz B získal zámky čtení, dotaz A by musel čekat na uvolnění zámků čtení dotazu B, než by mohl získat zámky zápisu. Dotaz B však neuvolní zámky čtení, dokud neskončí, a neskončí, pokud nebude moci získat zámky zápisu. Dotaz A a dotaz B jsou v patové situaci, a tudíž uvázlé.

Proto možná budete chtít provést explicitní uzamčení tabulky, abyste se vyhnuli velkému množství uzamčení záznamů (které využívají paměť a ovlivňují výkon), a abyste se vyhnuli uváznutí.

Alternativním přístupem je použití SELECT ... FOR UPDATE na vašem vnitřním SELECTu. Začíná to zámky zápisu na všech řádcích místo toho, aby se začínalo čtením a eskalací.

Odvozené tabulky

Pro vnitřní SELECT vytvoří MySQL odvozenou dočasnou tabulku. Odvozená tabulka je skutečná neindexovaná kopie dat, která se nachází v dočasné tabulce, která je automaticky vytvořena MySQL (na rozdíl od dočasné tabulky, kterou explicitně vytvoříte a můžete do ní přidávat indexy).

Protože MySQL používá odvozenou tabulku, je to dočasná stará hodnota, na kterou odkazujete ve své otázce. Jinými slovy, není zde žádná magie. MySQL to dělá stejně, jako byste to dělali kdekoli jinde, s dočasnou hodnotou.

Odvozenou tabulku můžete vidět provedením EXPLAIN proti vašemu příkazu UPDATE (podporováno v MySQL 5.6+).



  1. CURRENT_DATE/CURDATE() nefunguje jako výchozí hodnota DATE

  2. Certifikace Oracle

  3. Jak RLIKE funguje v MariaDB

  4. Úvod do Hadoopu a velkých dat