Bug #100493 | Cross schema foreign key blocks actions while stored functions are running | ||
---|---|---|---|
Submitted: | 11 Aug 2020 9:43 | Modified: | 12 Aug 2020 6:02 |
Reporter: | Andre Scheidtmann | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: DML | Severity: | S3 (Non-critical) |
Version: | 8.0.18 | OS: | Debian (18.04.) |
Assigned to: | CPU Architecture: | Any |
[11 Aug 2020 9:43]
Andre Scheidtmann
[11 Aug 2020 12:28]
MySQL Verification Team
Hi Mr. Scheidtmann, Thank you for your bug report. However, we need additional info. First of all, we would like to know whether you experience the same problem with 8.0.21. You are using an old release and there are hundreds of bugs fixed interim. Second, if and when you get a lock with 8.0.21, please send us a full output from InnoDB status, including all the locks being held.
[11 Aug 2020 16:09]
Erlend Dahl
# MTR repro testcase CREATE DATABASE shared; CREATE TABLE shared.shared_table (SharedID INT PRIMARY KEY); INSERT INTO shared.shared_table VALUES(1); CREATE DATABASE a; CREATE TABLE a.t (ID INT, SharedID INT); ALTER TABLE a.t ADD CONSTRAINT FK_a_SharedID FOREIGN KEY (SharedID) REFERENCES shared.shared_table (SharedID) ON UPDATE CASCADE ON DELETE CASCADE; CREATE DATABASE b; CREATE TABLE b.t (ID INT, SharedID INT); ALTER TABLE b.t ADD CONSTRAINT FK_b_SharedID FOREIGN KEY (SharedID) REFERENCES shared.shared_table (SharedID) ON UPDATE CASCADE ON DELETE CASCADE; DELIMITER |; CREATE FUNCTION a.test() RETURNS VARCHAR (255) READS SQL DATA BEGIN DECLARE result BOOL; SELECT SLEEP(20) FROM shared.shared_table INTO @blackhole; RETURN ''; END| DELIMITER ;| UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; # Session A --connect(conA, localhost, root,,) --connection conA --send SELECT a.test(); # Session B --connect(conB, localhost, root,,) --connection conB --send ALTER TABLE b.t DROP FOREIGN KEY FK_b_SharedID; # Default connection --connection default USE performance_schema; SELECT thread_id, processlist_command, processlist_state, processlist_info, object_type, object_schema, object_name, lock_type, lock_status FROM threads JOIN metadata_locks ON (metadata_locks.owner_thread\ _id = threads.thread_id) WHERE (object_schema = "shared"); --connection conA --reap --connection conB --reap --connection default --disconnect conA --disconnect conB DROP DATABASE a; DROP DATABASE b; DROP DATABASE shared;
[11 Aug 2020 16:10]
Erlend Dahl
Output from P_S shows that the alter is hanging on a metadata lock: SELECT thread_id, processlist_command, processlist_state, processlist_info, object_type, object_schema, object_name, lock_type, lock_status FROM threads JOIN metadata_locks ON (metadata_locks.owner_thread_id = threads.thread_id) WHERE (object_schema = "shared"); thread_id processlist_command processlist_state processlist_info object_type object_schema object_name lock_type lock_status 49 Query User sleep SELECT SLEEP(20) FROM shared.shared_table INTO @blackhole COLUMN STATISTICS shared shared_table SHARED_READ GRANTED 49 Query User sleep SELECT SLEEP(20) FROM shared.shared_table INTO @blackhole TABLE shared shared_table SHARED_READ GRANTED 49 Query User sleep SELECT SLEEP(20) FROM shared.shared_table INTO @blackhole SCHEMA shared NULL INTENTION_EXCLUSIVE GRANTED 50 Query Waiting for table metadata lock ALTER TABLE b.t DROP FOREIGN KEY FK_b_SharedID SCHEMA shared NULL INTENTION_EXCLUSIVE GRANTED 50 Query Waiting for table metadata lock ALTER TABLE b.t DROP FOREIGN KEY FK_b_SharedID TABLE shared shared_table SHARED_UPGRADABLE GRANTED 50 Query Waiting for table metadata lock ALTER TABLE b.t DROP FOREIGN KEY FK_b_SharedID TABLE shared shared_table EXCLUSIVE PENDING a.test()
[11 Aug 2020 16:11]
Erlend Dahl
8.0.18 and later versions behave in the same way.
[12 Aug 2020 6:02]
Andre Scheidtmann
I just found out that the stored function isn´t even needed to produce this behaviour. You just need to run a long query against the shared table. #Setup DROP DATABASE IF EXISTS a; DROP DATABASE IF EXISTS b; DROP DATABASE IF EXISTS shared; CREATE DATABASE shared; CREATE TABLE shared.shared_table (SharedID INT PRIMARY KEY); INSERT INTO shared.shared_table VALUES(1); CREATE DATABASE a; CREATE TABLE a.t (ID INT, SharedID INT); ALTER TABLE a.t ADD CONSTRAINT FK_a_SharedID FOREIGN KEY (SharedID) REFERENCES shared.shared_table (SharedID) ON UPDATE CASCADE ON DELETE CASCADE; CREATE DATABASE b; CREATE TABLE b.t (ID INT, SharedID INT); ALTER TABLE b.t ADD CONSTRAINT FK_b_SharedID FOREIGN KEY (SharedID) REFERENCES shared.shared_table (SharedID) ON UPDATE CASCADE ON DELETE CASCADE; # Session A SELECT SLEEP(60) FROM shared.shared_table; # Session B ALTER TABLE b.t DROP FOREIGN KEY FK_b_SharedID;
[12 Aug 2020 13:14]
MySQL Verification Team
Thank you, Erlend.
[14 Aug 2020 3:40]
Erlend Dahl
Posted by developer: Comment from one of the MySQL architects (Dmitry L): unfortunately for the user it looks like the expected result of addition of MDL locking for foreign keys in 8.0. We need to acquire an exclusive lock on the parent table at some point when we add FK, hence concurrent usage of parent table by long running trxes and addition of FKs is problematic.