** Редактирано **
Избиране от целевата таблица
От 13.2.9.8. Подзаявки в клаузата FROM:
Подзаявките в клаузата FROM могат да върнат скалар, колона, ред или таблица. Подзаявките в клаузата FROM не могат да бъдат корелирани подзаявки, освен ако не се използват в клаузата ON на операция JOIN.
Така че, да, можете да изпълните горната заявка.
Проблемът
Тук наистина има два проблема. Има едновременност или гарантиране, че никой друг не променя данните изпод краката ни. Това се обработва със заключване. Справянето с действителната промяна на нови спрямо стари стойности се обработва с производни таблици.
Заключване
В случай на вашата заявка по-горе, с InnoDB, MySQL първо изпълнява SELECT и придобива заключване за четене (споделено) на всеки ред в таблицата поотделно. Ако имате клауза WHERE в израза SELECT, тогава само записите, които изберете, ще бъдат заключени, където диапазоните също биха довели до блокиране на пропуските.
Заключването на четене не позволява на всяка друга заявка да придобие заключвания за запис, така че записите не могат да се актуализират от другаде, докато са заключени за четене.
След това MySQL придобива заключване на запис (изключително) на всеки от записите в таблицата поотделно. Ако сте имали клауза WHERE във вашия оператор UPDATE, тогава само конкретните записи ще бъдат заключени и отново, ако клаузата WHERE избере диапазон, тогава ще имате заключен диапазон.
Всеки запис, който има заключване за четене от предишния SELECT, автоматично ще бъде ескалиран до заключване на запис.
Заключването на запис не позволява на други заявки да получат заключване за четене или запис.
Можете да използвате Innotop, за да видите това, като го стартирате в режим на заключване, стартирате транзакция, изпълните заявката (но не я извършвайте) и ще видите ключалките в Innotop. Освен това можете да видите подробностите без Innotop с SHOW ENGINE INNODB STATUS
.
Застой
Вашата заявка е уязвима към задънена улица, ако два екземпляра се изпълняват едновременно. Ако заявка A получи заключвания за четене, тогава заявка B получи заключвания за четене, заявка A ще трябва да изчака освобождаването на заключванията за четене на заявка B, преди да може да придобие заключванията за запис. Въпреки това, заявка B няма да освободи заключванията за четене, докато не приключи, и няма да завърши, освен ако не може да придобие заключвания за запис. Заявка А и заявка Б са в безизходица и следователно в задънена улица.
Следователно може да пожелаете да извършите изрично заключване на таблицата, както за да избегнете огромното количество заключвания на записи (което използва памет и влияе на производителността), така и за да избегнете блокиране.
Алтернативен подход е да използвате SELECT ... FOR UPDATE във вашия вътрешен SELECT. Това започва със заключвания за запис на всички редове, вместо да се започне с четене и да ги ескалира.
Производни таблици
За вътрешния SELECT MySQL създава извлечена временна таблица. Произведената таблица е действително неиндексирано копие на данните, които живеят във временната таблица, която се създава автоматично от MySQL (за разлика от временна таблица, която изрично създавате и към която можете да добавяте индекси).
Тъй като MySQL използва извлечена таблица, това е временната стара стойност, за която се позовавате във вашия въпрос. С други думи, тук няма магия. MySQL го прави точно както бихте го направили навсякъде другаде, с временна стойност.
Можете да видите получената таблица, като направите EXPLAIN срещу вашия оператор UPDATE (поддържа се в MySQL 5.6+).