Mysql 如何提高插入到。。。选择锁定行为

Mysql 如何提高插入到。。。选择锁定行为,mysql,select,insert,locking,innodb,Mysql,Select,Insert,Locking,Innodb,在我们的生产数据库中,我们每小时运行一次以下伪代码SQL批处理查询: INSERT INTO TemporaryTable (SELECT FROM HighlyContentiousTableInInnoDb WHERE allKindsOfComplexConditions are true) 现在,这个查询本身不需要很快,但我注意到它锁定了InNODB中的高内容表,即使它只是从中读取。这使得其他一些非常简单的查询需要大约25秒(这就是其他查询需要的时间) 然后我发现在这

在我们的生产数据库中,我们每小时运行一次以下伪代码SQL批处理查询:

INSERT INTO TemporaryTable
    (SELECT FROM HighlyContentiousTableInInnoDb
     WHERE allKindsOfComplexConditions are true)
现在,这个查询本身不需要很快,但我注意到它锁定了InNODB中的高内容表,即使它只是从中读取。这使得其他一些非常简单的查询需要大约25秒(这就是其他查询需要的时间)

然后我发现在这种情况下,InnoDB表实际上是被SELECT锁定的


但我并不真的喜欢文章中选择一个输出文件的解决方案,它看起来像一个黑客(文件系统上的临时文件看起来很糟糕)。还有其他想法吗?是否有一种方法可以创建InnoDB表的完整副本,而不必在复制过程中以这种方式锁定它。然后我可以将
HighlyContentiousTable
复制到另一个表中并在那里执行查询。

您可能可以使用Create View命令(请参阅)。 比如说,

Create View temp as SELECT FROM HighlyContentiousTableInInnoDb WHERE allKindsOfComplexConditions are true
之后,可以将insert语句用于此视图。 像这样的

INSERT INTO TemporaryTable (SELECT * FROM temp)

这只是我的建议。

免责声明:我对数据库不是很有经验,我不确定这个想法是否可行。如果不是,请纠正我

在INNODB2中设置一个二级等效表
HighlyContentiousTable,并在第一个表中创建插入后的
触发器,该触发器使用相同的数据更新新表。现在,您应该能够锁定InNodeB2中的HighlyContentiousTable,并且只减慢主表的触发器,而不是所有查询

潜在问题:

  • 2 x存储的数据
  • 所有插入、更新和删除的附加工作
  • 可能在事务上不合理
锁定(readlock)的原因是为了确保您的读取事务不读取并行事务当前可能正在写入的“脏”数据。 大多数DBMS提供用户可以手动设置和撤销读写锁的设置。如果在您的案例中读取脏数据不是问题,那么这可能会让您感兴趣

我认为在具有多个事务的DBS中,没有任何安全的方法可以在没有任何锁的情况下读取表

但以下是一些头脑风暴: 如果空间没有问题,可以考虑运行同一个表的两个实例
highlycontentioustableinnodb2
用于持续读/写事务,而
highlycontentioustableinnodb2\u shadow
用于批处理访问。 也许您可以通过DBMS中的触发器/例程自动填充阴影表,这比在任何地方都添加一个写事务更快、更智能

另一个想法是:所有事务都需要访问整个表吗?
否则,可以使用视图仅锁定必要的列。如果连续访问和批处理访问在列方面是不相交的,那么它们可能不会相互锁定

如果允许某些异常,可以将隔离级别更改为最低严格的一读未提交。但在此期间,允许有人读取您的目标表。或者您可以手动锁定目标表(我假设mysql提供了这个功能?)

或者,您也可以使用readcommitted,它不应该也锁定源表。但它也会在提交之前锁定目标表中插入的行


我会选择第二个。

我不熟悉MySQL,但希望有一个与SQL Server中的事务隔离级别
Snapshot
Read committed Snapshot
相当的级别。使用其中任何一种方法都可以解决您的问题。

现在这个问题的答案要简单得多: -使用基于行的复制和读取提交的隔离级别

您正在经历的锁定消失

更长的解释:

每个使用Innodb表的人可能都习惯了Innodb这一事实 表执行非锁定读取,这意味着除非使用 修改器(如共享模式下的锁定)或用于更新的SELECT语句 运行时不会锁定任何行

这通常是正确的,但是有一个明显的例外——插入表1,从表2中选择*。此语句将对表2表执行锁定读取(共享锁)。它也适用于具有where子句和联接的类似表。对于正在被读取的表来说,将其作为Innodb是很重要的,即使写入是在MyISAM表中完成的

那么,为什么要这样做,这对MySQL的性能和性能都非常不利呢 并发性

原因是——复制。在MySQL 5.1之前的版本中,复制是基于语句的,这意味着在主服务器上回复的语句应该与在从服务器上回复的语句产生相同的效果。如果Innodb不锁定源表中的行,则其他事务可以在运行INSERT的事务之前修改该行并提交。。SELECT语句。这将使该事务在INSERT…SELECT语句之前应用于从机,并可能导致与主机不同的数据。读取源表中的行时锁定这些行可以防止这种影响,因为其他事务会在插入之前修改行…如果SELECT有机会访问这些行,则也会在从属表上以相同的顺序修改这些行。如果事务在访问该行并被INSERT…SELECT锁定后尝试修改该行,则事务必须等待语句完成,以确保它将以正确的顺序在从属服务器上执行。变得很复杂?您需要知道的是,在5.1之前的MySQL中,必须先完成复制才能正常工作

在MySQL 5.1中,这一问题以及其他一些问题都应该通过基于行的复制来解决。然而,我还没有给它进行真正的压力测试,看看它的表现有多好:)

还有一件事需要考虑–INSERT…SELECT实际上在锁定模式下执行读取,因此部分绕过版本控制并检索最新提交的行。所以即使你是
SET GLOBAL binlog_format = 'ROW';
[mysqld]
binlog_format=ROW
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
INSERT INTO t1 SELECT ....;
SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
[mysqld]
transaction-isolation = READ-UNCOMMITTED
LOCK TABLES HighlyContentiousTableInInnoDb READ;
INSERT INTO TemporaryTable
    (SELECT FROM HighlyContentiousTableInInnoDb
    WHERE allKindsOfComplexConditions are true)
UNLOCK TABLES;