sql >> Databáze >  >> RDS >> PostgreSQL

Chyba v zamykacím mechanismu PostgreSQL nebo nepochopení mechanismu

Není tam žádná chyba a nemyslím si, že něčemu nerozumíte; chybí vám jen pár kousků skládačky.

Cizí klíče jsou implementovány interně pomocí zamykání na úrovni řádků; počínaje Postgres 8.1 a až 9.2, kdykoli aktualizujete tabulku odkazů (apples v tomto případě) se spustí dotaz, který provede SELECT FOR SHARE v odkazované tabulce (trees ). Takže SELECT FOR UPDATE v prvním bloku transakce SELECT FOR SHARE referenční integrity pro druhou transakci. To způsobuje blok ve druhém příkazu.

Teď tě slyším křičet:„Počkej! Jak to, že blokuje druhý příkaz a ne první? Vysvětlení je opravdu jednoduché -- to jen proto, že existuje jednoduchá optimalizace, která přeskočí interní SELECT FOR SHARE když se klíč nemění. To je však zjednodušené v tom, že pokud aktualizujete n-tici podruhé, tato optimalizace se nespustí, protože je těžší vystopovat původní hodnoty. Proto ta blokáda.

Možná se také divíte, proč jsem řekl, že je to až 9.2 --- co je s 9.3? Hlavní rozdíl je v tom, že v 9.3 používá SELECT FOR KEY SHARE , což je nová, lehčí úroveň zámku; umožňuje lepší souběh. Pokud vyzkoušíte svůj příklad v 9.3 a také změňte SELECT FOR UPDATE na SELECT FOR NO KEY UPDATE (což je lehčí režim než SELECT FOR UPDATE to říká, že se možná chystáte aktualizovat n-tici, ale slíbíte, že nezměníte primární klíč a slíbíte, že ho nesmažete), měli byste vidět, že se neblokuje. (Můžete také zkusit UPDATE na odkazovaném řádku, a pokud nezměníte primární klíč, pak se také nezablokuje.)

Tato věc 9.3 byla představena vaším patchem skutečně jako http://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=0ac5ad5134f2769ccbaefec73844f8504c4d6182 a myslím, že to byl docela skvělý hack (zpráva o odevzdání obsahuje nějaké další podrobnosti, pokud vám na takových věcech záleží). Ale pozor, nepoužívejte verze starší než 9.3.4, protože tato oprava byla tak nesmírně složitá, že několik závažných chyb zůstalo bez povšimnutí a opravili jsme je teprve nedávno.




  1. Převeďte datum mysql (datetime) do lepšího formátu data pomocí php

  2. PostgreSQL poddotaz pomocí like

  3. Mysql vyberte rekurzivní získat všechny dítě s více úrovněmi

  4. Vyberte odlišná první slova pole