每次我使用MySQL CREATE TABLE AS SELECT ...
时,所有选择的表/索引都会锁定查询的持续时间。我真的不明白为什么?有没有办法解决这个问题?
使用: MySQL 5.1.41
和InnoDB
添加了示例:
例如,以下查询最多可能需要10分钟才能完成:
CREATE TABLE temp_lots_of_data_xxx AS
SELECT
a.*
b.*
c.*
FROM a
LEFT JOIN b ON a.foo = b.foo
LEFT JOIN c ON a.foo = c.foo
在上述查询期间尝试更新表a,b或c中的值将等待上述查询首先完成。我想避免这种锁,因为我对创建的临时表中最完整的数据不感兴趣。
P.S。 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
行为没有变化。
答案 0 :(得分:12)
另见 http://www.mysqlperformanceblog.com/2006/07/12/insert-into-select-performance-with-innodb-tables/
如果不使用复制,可以更改innodb_locks_unsafe_for_binlog以更改此锁定行为。
或者可以将数据转储到文件,然后从文件重新加载数据。这也避免了锁。
答案 1 :(得分:6)
您是否尝试分两个阶段进行操作(首先创建表,然后插入值)并设置最低隔离级别?:
CREATE TABLE temp_lots_of_data_xxx AS
SELECT
a.*
b.*
c.*
FROM a
LEFT JOIN b ON a.foo = b.foo
LEFT JOIN c ON a.foo = c.foo
WHERE FALSE
INSERT INTO temp_lots_of_data_xxx
SELECT
a.*
b.*
c.*
FROM a
LEFT JOIN b ON a.foo = b.foo
LEFT JOIN c ON a.foo = c.foo
答案 2 :(得分:3)
我没有对此进行测试,但您可能会尝试使用
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
CREATE TABLE ...
COMMIT ; /*See comment by Somnath Muluk*/
但请注意:
Select语句以非锁定方式执行,但是a 可能会使用行的早期版本。因此,使用这个 隔离级别,这种读取不一致。这也称为a “脏读。”
在这里阅读更多相关信息:
MySQL SET TRANSACTION manual entry
编辑:添加了COMMIT ;
答案 3 :(得分:2)
我的通灵调试技巧表明,在调试使用它们的查询时,您正试图访问表/索引。
一般情况下,如果CREATE TABLE查询锁定了它正在读取的所有表和索引,我不会感到惊讶。
如果我的心理预感是正确的,我建议在访问它正在使用的表和索引之前让查询完成。
(如果我做出任何错误的假设,请纠正我。)
答案 4 :(得分:2)
交易所持有的所有InnoDB锁都会被释放 交易已提交或中止。因此,它没有多大意义 在autocommit = 1模式下调用InnoDB表上的LOCK TABLES,因为 获得的InnoDB表锁将立即释放。
阅读here
编辑,并且:
您无法在事务中锁定其他表 因为LOCK TABLES执行隐式COMMIT和UNLOCK TABLES。
答案 5 :(得分:2)
如果你的引擎是InnoDB而不是它使用自动行级锁定。更新语句比select语句具有更高的优先级,这就是您遇到此问题的原因。
为了解决此问题,您可以SET LOW_PRIORITY_UPDATES=1
,然后您应该能够运行您的命令。但这并不完全适合您的情况。因此,您也可以优先考虑SELECT
语句。要为特定SELECT
语句提供更高优先级,请使用HIGH_PRIORITY
属性。
CREATE TABLE temp_lots_of_data_xxx AS
SELECT HIGH_PRIORITY
a.*
b.*
c.*
FROM a
LEFT JOIN b ON a.foo = b.foo
LEFT JOIN c ON a.foo = c.foo
有关详细信息,请参阅此页table-locking-issues此页面select-syntax以及此页面:option_mysqld_low-priority-updates
答案 6 :(得分:1)
我对mysql没有经验,但我在mssql中遇到了同样的问题。解决方案是运行“create table as select ...”,零行,以便它只创建具有适当结构的表并立即释放锁。然后使用“insert into”和相同的select语句来填充表,该表在运行时不会保存任何模式锁。