Mysql:在更新查询中使用嵌套选择查询会创建死锁

问题描述 投票:1回答:1

我正在尝试根据同一张表中的选择来更新列。查询:

update tasks_queue as t1, (select id from tasks_queue where (user_id>=1230000000000000) and (user_id<=1230099999999999) and (scheduled_at <= 1590584573882 and picked_at <= 1590583673882) order by priority_level asc, scheduled_at asc  limit 0, 1  for update) as t2 set pickup_id = '172.31.29.45-1590584573882-2729', picked_at = 1590584573882 where (user_id>=1230000000000000) and (user_id<=1230099999999999) and (scheduled_at <= 1590584573882 and picked_at <= 1590583673882 and t1.id = t2.id)

并尝试使用以下查询弹出记录。

select raw_data from tasks_queue where pickup_id = '172.31.29.45-1590584573882-2729'

有更多的Java线程用于从task_queue表中拾取。

表的架构如下。

     CREATE TABLE `tasks_queue` (
  `id` bigint(18) NOT NULL,
  `user_id` bigint(18) NOT NULL,
  `scheduled_at` bigint(13) NOT NULL,
  `source_type` tinyint(2) NOT NULL,
  `source_id` bigint(18) DEFAULT NULL,
  `priority_level` smallint(6) NOT NULL,
  `picked_at` bigint(13) DEFAULT NULL,
  `pickup_id` varchar(45) DEFAULT NULL,
  `raw_data` longtext NOT NULL,
  PRIMARY KEY (`id`),
  KEY `scheduled_picked_at_idx` (`scheduled_at`,`picked_at`),
  KEY `user_id_idx` (`user_id`),
  KEY `pickup_id` (`pickup_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

死锁转储信息

2020-05-27T13:02:53.889027Z 82092 [Note] InnoDB: Transactions deadlock detected, dumping detailed information.
2020-05-27T13:02:53.889048Z 82092 [Note] InnoDB: 
*** (1) TRANSACTION:

TRANSACTION 1394376833, ACTIVE 0 sec fetching rows
mysql tables in use 2, locked 2
LOCK WAIT 18 lock struct(s), heap size 1136, 163 row lock(s)
MySQL thread id 80724, OS thread handle 140642529179392, query id 2122809 ip-172-31-29-45.ap-south-1.compute.internal 172.31.29.45 mpix Creating sort index
update tasks_queue as t1, (select id from tasks_queue where (user_id>=1230000000000000) and (user_id<=1230099999999999) and (scheduled_at <= 1590584573882 and picked_at <= 1590583673882) order by priority_level asc, scheduled_at asc  limit 0, 1  for update) as t2 set pickup_id = '172.31.29.45-1590584573882-2729', picked_at = 1590584573882 where (user_id>=1230000000000000) and (user_id<=1230099999999999) and (scheduled_at <= 1590584573882 and picked_at <= 1590583673882 and t1.id = t2.id)
2020-05-27T13:02:53.889099Z 82092 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 123642 page no 10 n bits 80 index PRIMARY of table `dspace3`.`tasks_queue` trx id 1394376833 lock_mode X waiting
Record lock, heap no 8 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 8; hex 80000000074cf829; asc      L );;
 1: len 6; hex 0000531c807f; asc   S   ;;
 2: len 7; hex c5000001980110; asc        ;;
 3: len 8; hex 80045eadb112e001; asc   ^     ;;
 4: len 8; hex 80000172563a7fb4; asc    rV:  ;;
 5: len 1; hex 81; asc  ;;
 6: len 8; hex 80045eadecadaa6d; asc   ^    m;;
 7: len 2; hex 8064; asc  d;;
 8: len 8; hex 8000000000000000; asc         ;;
 9: SQL NULL;
 10: len 8; hex 80045eaded5773fe; asc   ^  Ws ;;
 11: len 30; hex (total 1126 bytes);

2020-05-27T13:02:53.895025Z 82092 [Note] InnoDB: *** (2) TRANSACTION:

TRANSACTION 1394376831, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
4 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 82092, OS thread handle 140641975121664, query id 2122814 ip-172-31-29-45.ap-south-1.compute.internal 172.31.29.45 mpix update
insert into tasks_queue (id,user_id,scheduled_at,source_type,source_id,priority_level,raw_data,picked_at) VALUES (-1403646261, 1230000000000001, 1590584573881, 1, 1230001000000109, 100, 'the payload dataa 
2020-05-27T13:02:53.895064Z 82092 [Note] InnoDB: *** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 123642 page no 10 n bits 80 index PRIMARY of table `dspace3`.`tasks_queue` trx id 1394376831 lock_mode X locks rec but not gap
Record lock, heap no 8 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 8; hex 80000000074cf829; asc      L );;
 1: len 6; hex 0000531c807f; asc   S   ;;
 2: len 7; hex c5000001980110; asc        ;;
 3: len 8; hex 80045eadb112e001; asc   ^     ;;
 4: len 8; hex 80000172563a7fb4; asc    rV:  ;;
 5: len 1; hex 81; asc  ;;
 6: len 8; hex 80045eadecadaa6d; asc   ^    m;;
 7: len 2; hex 8064; asc  d;;
 8: len 8; hex 8000000000000000; asc         ;;
 9: SQL NULL;
 10: len 8; hex 80045eaded5773fe; asc   ^  Ws ;;
 11: len 30; hex test;

2020-05-27T13:02:53.895515Z 82092 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 123642 page no 23 n bits 80 index PRIMARY of table `dspace3`.`tasks_queue` trx id 1394376831 lock_mode X locks gap before rec insert intention waiting
Record lock, heap no 11 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 8; hex 7fffffffac99114e; asc        N;;
 1: len 6; hex 0000531c807c; asc   S  |;;
 2: len 7; hex c20000c0310266; asc     1 f;;
 3: len 8; hex 80045eadb112e001; asc   ^     ;;
 4: len 8; hex 80000172563a7f93; asc    rV:  ;;
 5: len 1; hex 81; asc  ;;
 6: len 8; hex 80045eadecadaa6d; asc   ^    m;;
 7: len 2; hex 8064; asc  d;;
 8: len 8; hex 8000000000000000; asc         ;;
 9: SQL NULL;
 10: len 8; hex 80045eaded5761ef; asc   ^  Wa ;;
 11: len 30; hex 4461696c796f6e6c696e654a6f62733c6e6f2d7265706c79406461696c79; asc Daily<no-reply@daily; (total 1125 bytes);

2020-05-27T13:02:53.896735Z 82092 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)

有人可以解释为什么会发生僵局吗?

更新:死锁是由于MySQL索引间隙锁定而发生的。更新语句中的嵌套选择查询将锁定已扫描的记录索引,同时也锁定索引间隙。我希望这可以帮助别人。

mysql database-deadlocks nested-queries
1个回答
1
投票

锁定是由于使用FOR UPDATE,如果您这样做是怎么办?

REF:mySQL Locking

update 
 tasks_queue t1
set 
 pickup_id = '172.31.29.45-1590584573882-2729',
 picked_at = 1590584573882
where
 (user_id>=1230000000000000) 
and 
 (user_id<=1230099999999999) 
and 
 (scheduled_at <= 1590584573882 and picked_at <= 1590583673882)
and
 t1.id in (
  select
   id
  from
   tasks_queue
  where
   (user_id>=1230000000000000)
  and
   (user_id<=1230099999999999)
  and
   (scheduled_at <= 1590584573882 and picked_at <= 1590583673882)
  order by
   priority_level asc, scheduled_at asc
  limit
   0, 1 
 )
© www.soinside.com 2019 - 2024. All rights reserved.