锁的总数超过了锁表大小

时间:2011-08-01 15:59:22

标签: mysql sql

我正在MySQL中运行报告。其中一个查询涉及将大量行插入临时表。当我尝试运行它时,我收到此错误:

错误代码1206:锁的数量超过了锁表大小。

有问题的查询是:

create temporary table SkusBought(
customerNum int(11),
sku int(11),
typedesc char(25),
key `customerNum` (customerNum)
)ENGINE=InnoDB DEFAULT CHARSET=latin1;
insert into skusBought
select t1.* from
    (select customer, sku, typedesc from transactiondatatransit
    where (cat = 150 or cat = 151)
    AND daysfrom07jan1 > 731
group by customer, sku
union
select customer, sku, typedesc from transactiondatadelaware
    where (cat = 150 or cat = 151)
    AND daysfrom07jan1 > 731
group by customer, sku
union
select customer, sku, typedesc from transactiondataprestige
    where (cat = 150 or cat = 151)
    AND daysfrom07jan1 > 731
group by customer, sku) t1
join
(select customernum from topThreetransit group by customernum) t2
on t1.customer = t2.customernum;

我已经读过,更改配置文件以增加缓冲池大小会有所帮助,但这没有任何作用。解决这个问题的方法是临时解决方法还是永久解决方法?

编辑:更改了部分查询。不应该影响它,但我做了一个发现 - 替换所有,并没有意识到它搞砸了。不影响这个问题。

编辑2:将typedesc添加到t1。我在查询中更改了它但不在此处。

11 个答案:

答案 0 :(得分:49)

可以通过设置MySQL变量innodb_buffer_pool_size的较高值来解决此问题。 innodb_buffer_pool_size的默认值为8,388,608

要更改innodb_buffer_pool_size的设置值,请参阅以下设置。

  1. 从服务器中找到文件my.cnf。对于Linux服务器,这主要是/etc/my.cnf
  2. 将行innodb_buffer_pool_size=64MB添加到此文件
  3. 重启MySQL服务器
  4. 要重启MySQL服务器,您可以使用以下两个选项中的任何一个:

    1. service mysqld restart
    2. /etc/init.d/mysqld restart
    3. 参考The total number of locks exceeds the lock table size

答案 1 :(得分:21)

我找到了解决它的另一种方法 - 使用Table Lock。当然,如果您需要同时更新表格,它可能不适合您的应用程序。

请参阅: 尝试使用LOCK TABLES来锁定整个表,而不是InnoDB的MVCC行级锁定的默认操作。如果我没有弄错的话,“锁定表”指的是InnoDB内部结构,它存储了MVCC实现的行和版本标识符,其中一位标识正在语句中修改行,并且具有6000万行的表,可能超过分配给它的内存。 LOCK TABLES命令应该通过设置表级锁而不是行级来缓解此问题:

SET @@AUTOCOMMIT=0;
LOCK TABLES avgvol WRITE, volume READ;
INSERT INTO avgvol(date,vol)
SELECT date,avg(vol) FROM volume
GROUP BY date;
UNLOCK TABLES;
Jay Pipes, 北美社区关系经理,MySQL Inc.

答案 2 :(得分:13)

来自MySQL documentation(您已经阅读过的内容):

  

1206(ER_LOCK_TABLE_FULL)

     

锁的总数超过了锁表大小。要避免此错误,请增加innodb_buffer_pool_size的值。在单个应用程序中,解决方法可能是将大型操作分解为更小的部分。 例如,如果大型INSERT发生错误,请执行几个较小的INSERT操作。

如果增加 innodb_buffer_pool_size 没有帮助,那么只需按照粗体部分上的指示并将你的INSERT拆分为3.跳过UNION并制作3个INSERT,每个INSERT都加入 topThreetransit 表。

答案 3 :(得分:2)

如果你已经正确地构建了表,以便每个表包含相对唯一的值,那么执行此操作的方法不那么强烈,就是执行3个单独的insert-into语句,每个表1个,并使用join-filter每个插入 -

INSERT INTO SkusBought...

SELECT t1.customer, t1.SKU, t1.TypeDesc
FROM transactiondatatransit AS T1
LEFT OUTER JOIN topThreetransit AS T2
ON t1.customer = t2.customernum
WHERE T2.customernum IS NOT NULL

对其他两个表重复此操作 - 复制/粘贴是一个很好的方法,只需更改FROM表名即可。 **如果您试图阻止SkusBought表中的重复条目,您可以在WHERE子句之前的每个部分中添加以下连接代码。

LEFT OUTER JOIN SkusBought AS T3
ON  t1.customer = t3.customer
AND t1.sku = t3.sku

- 然后是WHERE子句的最后一行 -

AND t3.customer IS NULL

您的初始代码使用了许多子查询,并且UNION语句可能很昂贵,因为它会首先创建自己的临时表来填充来自三个单独源的数据,然后插入到您希望ALONG运行的表中另一个用于过滤结果的子查询。

答案 4 :(得分:2)

Windows中的

:如果你有mysql工作台。转到服务器状态。在我的情况下找到运行服务器文件的位置:

C:\ProgramData\MySQL\MySQL Server 5.7

打开my.ini文件并找到buffer_pool_size。将值设置为高。默认值为8M。 这就是我解决这个问题的方法

答案 5 :(得分:1)

我正在使用MySql工作台运行MySQL窗口。 转到服务器>服务器状态 在顶部,它说配置文件:“path”(C:\ProgramData\MySQL\...\my.ini

然后在文件“my.ini”中按控制+ F并找到buffer_pool_size。 设置值更高,我建议64MB(默认为8MB)。

转到Instance> Startup / Shutdown>重新启动sruver。停止服务器(然后再次启动服务器)

在我的情况下,我无法删除表格中的条目。

答案 6 :(得分:1)

首先,您可以使用sql命令show global variables like 'innodb_buffer%';来检查缓冲区大小。

解决方案是找到您的my.cnf文件并添加,

[mysqld]
innodb_buffer_pool_size=1G # depends on your data and machine

请勿忘记添加[mysqld],否则将无法正常工作。

就我而言, ubuntu 16.04 my.cnf位于文件夹/etc/mysql/下。

答案 7 :(得分:1)

修复错误代码1206:锁的数量超过了锁表的大小。

就我而言,我使用在Windows上使用WampServer 2.5运行的MySQL Workbench(5.6.17)。

对于Windows / WampServer,您必须编辑my.ini文件(而不是my.cnf文件)

要找到此文件,请转到菜单服务器/服务器状态(在MySQL Workbench中),然后在服务器目录/基本目录

下查找

MySQL Server - Server Status

在my.ini文件中,为不同的设置定义了部分,查找[mysqld]部分(如果不存在则创建该部分)并添加命令: innodb_buffer_pool_size = 4G

[mysqld]
innodb_buffer_pool_size = 4G

buffer_pool文件的大小取决于您的特定计算机,在大多数情况下,2G或4G将解决此问题。

请记住重新启动服务器,以便采用新配置,它为我解决了该问题。

希望有帮助!

答案 8 :(得分:1)

同一问题,我在运行sql脚本时进入了 MYSQL ,请查看下图。 Error code 1206: The number of locks exceeds the lock table size Picture

这是Mysql配置问题,因此我在<div class="block-editor"> <!-- editor control --> <div class="block-editor-control"> <ul> <li data-action="bold"> B </li> </ul> </div> <!-- editor content's --> <div class="block-editor-content"> <div class="block-editor-block" contenteditable="true" role="group"> Voldemort is back </div> </div> </div> 中进行了一些更改 并且它正在我的系统上工作并且问题已解决。

我们需要对let arr = [ [ ['firstName', 'Joe'], ['age', 42], ['gender', 'male'], ], [ ['firstName', 'Mary'], ['lastName', 'Jenkins'], ['age', 36], ['gender', 'female'], ], [ ['lastName', 'Kim'], ['age', 40], ['gender', 'female'], ], ]; 进行一些更改,这些更改可在以下路径上找到:- function test5(arr) { let result =[] arr.map(function(ele){ for(let i=0; i < ele.length; i++){ if(ele[i][0]==='firstName'||ele[i][0]==='lastName'){ result.push(ele[i][1]) } if(ele[i][0]==='age'){ result.push(ele[i][1]) } } }) return result } 并请在%dw 2.0 output application/json --- { result: payload mapObject ( (lower ('$$')): $ ) } 配置文件字段中更新以下更改:-

my.ini

完成所有上述更改后,请重新启动 MYSQL服务。 请参考图片:-Microsoft MYSQL Service Picture

答案 9 :(得分:0)

值得一提的是,用于此设置的数字是在BYTES中 - 找到了困难的方法!

答案 10 :(得分:0)

  

下面的答案不能直接回答OP的问题。然而,   我在此处添加此答案,因为此页面是   您的Google“锁总数超过了锁表的大小”。

如果您正在运行的查询正在分析跨越数百万行的整个表,则可以尝试使用while循环,而不用更改配置中的限制。

一会儿看起来会把它弄成碎片。下面是循环遍历DATETIME的索引列的示例。

# Drop
DROP TABLE IF EXISTS
new_table;

# Create (we will add keys later)
CREATE TABLE
new_table
(
    num INT(11),
    row_id VARCHAR(255),
    row_value VARCHAR(255),
    row_date DATETIME
);

# Change the delimimter
DELIMITER //

# Create procedure
CREATE PROCEDURE do_repeat(IN current_loop_date DATETIME)
BEGIN

    # Loops WEEK by WEEK until NOW(). Change WEEK to something shorter like DAY if you still get the lock errors like.
    WHILE current_loop_date <= NOW() DO

        # Do something
        INSERT INTO
            user_behavior_search_tagged_keyword_statistics_with_type
            (
                num,
                row_id,
                row_value,
                row_date
            )
        SELECT
            # Do something interesting here
            num,
            row_id,
            row_value,
            row_date
        FROM
            old_table
        WHERE
            row_date >= current_loop_date AND
            row_date < current_loop_date + INTERVAL 1 WEEK;

        # Increment
        SET current_loop_date = current_loop_date + INTERVAL 1 WEEK;

    END WHILE;

END//

# Run
CALL do_repeat('2017-01-01');

# Cleanup
DROP PROCEDURE IF EXISTS do_repeat//

# Change the delimimter back
DELIMITER ;

# Add keys
ALTER TABLE
    new_table
MODIFY COLUMN
    num int(11) NOT NULL,
ADD PRIMARY KEY
    (num),
ADD KEY
    row_id (row_id) USING BTREE,
ADD KEY
    row_date (row_date) USING BTREE;

如果您的表不使用日期,您也可以对其进行调整以遍历“ num”列。

希望这对某人有帮助!