Mysql
 sql >> база данни >  >> RDS >> Mysql

Колко реда ще бъдат заключени от SELECT ... ORDER BY xxx LIMIT 1 ЗА АКТУАЛИЗИРАНЕ?

Това е страхотен въпрос. InnoDB е механизъм за заключване на ниво ред, но той трябва да зададе допълнителни ключалки, за да гарантира безопасността с двоичния дневник (използван за репликация; възстановяване на точка във времето). За да започнете да го обяснявате, разгледайте следния (наивен) пример:

session1> START TRANSACTION;
session1> DELETE FROM users WHERE is_deleted = 1; # 1 row matches (user_id 10), deleted.
session2> START TRANSACTION;
session2> UPDATE users SET is_deleted = 1 WHERE user_id = 5; # 1 row matches.
session2> COMMIT;
session1> COMMIT;

Тъй като операторите се записват в двоичния регистрационен файл само след като бъдат записани, за подчинената сесия №2 ще се приложи първа и ще доведе до различен резултат, водещ до повреда на данните .

Така че това, което InnoDB прави, е да задава допълнителни ключалки. Ако is_deleted е индексиран, то преди сесия1 да извърши ангажимент, никой друг няма да може да промени или да вмъкне в диапазона на записи, където is_deleted=1 . Ако няма индекси в is_deleted , тогава InnoDB трябва да заключи всеки ред в цялата таблица, за да се увери, че повторението е в същия ред. Можете да мислите за това като заключване на празнината , което е различна концепция за разбиране от директното заключване на ниво ред .

Във вашия случай с този ORDER BY position ASC , InnoDB трябва да се увери, че не могат да се променят нови редове между най-ниската ключова стойност и "специална" най-ниска възможна стойност. Ако сте направили нещо като ORDER BY position DESC .. добре, тогава никой не може да вмъкне в този диапазон.

И така, тук идва решението:

  • Двоично регистриране на базата на изказвания е гадно. Наистина очаквам с нетърпение бъдеще, в което всички ще преминем към ред базирано на двоичен журнал (достъпно от MySQL 5.1, но не е включено по подразбиране).

  • При репликация, базирана на ред, ако промените нивото на изолация на четене-задължено, тогава само единият ред, който съвпада, трябва да бъде заключен.

  • Ако искате да сте мазохист, можете също да включите innodb_locks_unsafe_for_binlog с репликация, базирана на изрази.

Актуализация на 22 април :За да копирате + поставите моята подобрена версия на вашия тестов пример (не търсеше „в празнината“):

session1> CREATE TABLE test (id int not null primary key auto_increment, data1 int, data2 int, INDEX(data1)) engine=innodb;
Query OK, 0 rows affected (0.00 sec)

session1> INSERT INTO test VALUES (NULL, 1, 2), (NULL, 2, 1), (5, 2, 2), (6, 3, 3), (3, 3, 4), (4, 4, 3);
Query OK, 6 rows affected (0.00 sec)
Records: 6  Duplicates: 0  Warnings: 0

session1> start transaction;
Query OK, 0 rows affected (0.00 sec)

session1> SELECT id FROM test ORDER BY data1 LIMIT 1 FOR UPDATE;
+----+
| id |
+----+
|  1 |
+----+
1 row in set (0.00 sec)

session2> INSERT INTO test values (NULL, 0, 99); # blocks - 0 is in the gap between the lowest value found (1) and the "special" lowest value.

# At the same time, from information_schema:

localhost information_schema> select * from innodb_locks\G
*************************** 1. row ***************************
    lock_id: 151A1C:1735:4:2
lock_trx_id: 151A1C
  lock_mode: X,GAP
  lock_type: RECORD
 lock_table: `so5694658`.`test`
 lock_index: `data1`
 lock_space: 1735
  lock_page: 4
   lock_rec: 2
  lock_data: 1, 1
*************************** 2. row ***************************
    lock_id: 151A1A:1735:4:2
lock_trx_id: 151A1A
  lock_mode: X
  lock_type: RECORD
 lock_table: `so5694658`.`test`
 lock_index: `data1`
 lock_space: 1735
  lock_page: 4
   lock_rec: 2
  lock_data: 1, 1
2 rows in set (0.00 sec)

# Another example:
select * from test where id < 1 for update; # blocks


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да използвам 'distinct' в zend db модел

  2. Как да инсталирате MySQL Workbench на Windows

  3. как да дам същия сериен номер за група записи в mysql

  4. как да извлечете множество резултати от съхранена процедура на mysql в laravel

  5. Как да копирам таблица в MySQL