MySQL创建表作为SELECT

时间:2012-03-15 07:36:08

标签: mysql database

每次我使用MySQL CREATE TABLE AS SELECT ...时,所有选择的表/索引都会锁定查询的持续时间。我真的不明白为什么?有没有办法解决这个问题?

使用: MySQL 5.1.41InnoDB

添加了示例:

例如,以下查询最多可能需要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;行为没有变化。

7 个答案:

答案 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语句来填充表,该表在运行时不会保存任何模式锁。