Mar*_*cel 8 sql database query-optimization mariadb sql-insert
我有一个这样的SQL:
INSERT INTO table1 (column1, column2) (
SELECT column3, column4 FROM table2 WHERE column5 = 'value'
);
Run Code Online (Sandbox Code Playgroud)
table13,500,000 行。table2900,000 行。SELECT column3, column4 FROM table2 WHERE column5 = 'value'返回 NO 寄存器(零)并且需要大约 0.004 秒。INSERT INTO table1 (column1, column2) VALUES ('value', 'value')也需要约 0.004 秒。但是,当我将两者结合在一个INSERT INTO SELECT语句中时(如上所示),大约需要 7.7 秒。有解释吗?有解决办法吗?
性能下降的原因很简单。这是 InnoDB 对表 t2 执行锁定以防止(基于语句的)复制中出现不一致的少数情况之一。
来自 MySQL手册:
INSERT INTO T SELECT ... FROM S WHERE ... 在插入 T 的每一行上设置独占索引记录锁(不带间隙锁)。如果事务隔离级别是 READ COMMITTED,InnoDB 将在 S 上进行一致搜索读取(无锁)。否则,InnoDB 对 S 中的行设置共享下一个键锁。在后一种情况下,InnoDB 必须设置锁:在使用基于语句的二进制日志进行前滚恢复期间,每个 SQL 语句必须以完全相同的方式执行原来做的。
可能的解决方法(另请参阅 Harrison Fisk 的博客,写于 14 年前):
如果您使用基于语句的复制,可能唯一的解决方法是
SELECT * FROM table2 INTO outfile 'tmp.txt';
LOAD DATA INFILE 'tmp.txt' INTO TABLE table1;
Run Code Online (Sandbox Code Playgroud)
如果您使用基于行的复制,请将事务隔离级别设置为 READ COMMITTED。
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED
Run Code Online (Sandbox Code Playgroud)
另一个(不安全)选项是启用服务器变量innodb_locks_unsafe_for_binlog
小智 1
有时,当您使用 SELECT 执行 INSERT 时,性能会变慢,因为源表中的字段类型与目标表中的字段类型不同,因此当执行 INSERT-SELECT 时,会对 SELECT 中的值进行隐式强制转换,因此它们可以被坚持在命运表中。这种隐式转换并不是以最佳性能方式进行的,并且有时从值直接插入会更慢。
| 归档时间: |
|
| 查看次数: |
5989 次 |
| 最近记录: |