Загальна кількість замків перевищує розмір столу замків


76

Я запускаю звіт у 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;

Я читав, що зміна файлу конфігурації для збільшення розміру буферного пулу допоможе, але це нічого не робить. Яким був би спосіб виправити це, або як тимчасове рішення, або як постійне виправлення?

EDIT: змінено частину запиту. Це не повинно впливати, але я зробив пошук-заміну всіх і не зрозумів, що це все зіпсувало. Не впливає на питання.

EDIT 2: Додано typedesc до t1. Я змінив це у запиті, але не тут.


Чому ви групуєтесь у підвідбірках?
Тім

Мені важко це зрозуміти. Якщо t2.customernum = t1.customer, немає сенсу вибирати лише customernum з topThreetransit. Звичайно, SkusBought.typedesc - це той самий код клієнта, що і перший стовпець?
RedGrittyBrick

t2 - це підмножина клієнтів у t1. Приєднання полягає у позбавленні клієнтів у t1, які не входять у t2. Код для typedesc насправді неправильний. Знову ж таки, змінив його у фактичному скрипті sql, але не тут. Typedesc - це ще одна колонка транзакційних даних (усі три). Я зміню це так, щоб це було правильно, і це мало більше сенсу.
maxman92

Я написав спритні ілюстрації загальної проблеми тут
Дрю

Відповіді:


66

Цю проблему можна вирішити, встановивши вищі значення для змінної 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

Щоб перезапустити сервер MySQL, ви можете скористатися будь-яким із наведених нижче двох варіантів:

  1. перезапуск служби MySQL
  2. /etc/init.d/mysqld перезапустити

Довідка Загальна кількість замків перевищує розмір таблиці замків


1
Фокус полягає у пошуку та модифікації правильного файлу my.cnf. На моєму mac я маю щонайменше 20 файлів із цим ім’ям, застарілих від попередніх версій, ОС тощо. Файл my.cnf, який працював у мене після модифікації, як пропонувалось, був /usr/local/mysql-5.6.23-osx10. 8-x86_64 / my.cnf
Торен,

4
у Вампі - це my.ini
Енріке

Зверніть увагу, що мінімальний на сьогоднішній день становить 128 МБ, тож 64 МБ не працюватимуть, вам потрібно надати щось більше 128 МБ
Noam Rathaus

3
З MySQL 5.7.5 ви можете просто запустити SET GLOBAL innodb_buffer_pool_size=268435456;без пошуку файлу my.cnf та перезапуску mysql. stackoverflow.com/a/38333056/3553564
Клім

23

Я знайшов інший спосіб її вирішення - скористайтеся блокуванням таблиць. Звичайно, це може бути неприйнятним для вашої програми - якщо вам потрібно одночасно оновити таблицю.

Дивіться: Спробуйте скористатися LOCK TABLESдля блокування всієї таблиці замість дії за замовчуванням блокування рівня рядка MVCC InnoDB. Якщо я не помиляюся, "таблиця блокування" має на увазі внутрішню структуру InnoDB, що зберігає ідентифікатори рядків та версій для реалізації MVCC, з бітом, що ідентифікує рядок, модифікується у виписці та з таблицею в 60 мільйонів рядків, ймовірно перевищує виділену для нього пам’ять. 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;

Джей Пайпс, менеджер зі зв'язків із громадою, Північна Америка, MySQL Inc.


Я дотримувався вказівок у цій відповіді і не зазнав жодних покращень. У мене запущена версія 5.6.
mbmast

7
Це рішення не працювало і для мене, використовуючи Mysql 5.1. Можливо, це вже не працює для новіших версій?
frances

1
У моєму випадку рівень ізоляції не був важливим, і я змінив його на READ UNMMITED. Це вирішило проблему із замками. Але це залежить від вашого випадку використання. ВСТАНОВИТИ РІВЕНЬ ІЗОЛЯЦІЇ ТРАНЗАКЦІЇ, ПРОЧИТАНИЙ НЕЗАГОЛЕНО;
itstata

14

З документації MySQL (яку ви вже прочитали, як я бачу):

1206 (ER_LOCK_TABLE_FULL)

Загальна кількість замків перевищує розмір столу замків. Щоб уникнути цієї помилки, збільште значення innodb_buffer_pool_size. У межах окремого додатка обхідним шляхом може бути розбиття великої операції на менші частини. Наприклад, якщо помилка виникає для великого INSERT, виконайте кілька менших операцій INSERT.

Якщо збільшення innodb_buffer_pool_size не допомагає, просто виконайте вказівки в напівжирній частині та розділіть свій INSERT на 3. Пропустіть UNIONs і зробіть 3 INSERT, кожен із яких ПРИЄДНУЙТЕСЯ до таблиці topThreetransit .


5

По-перше, ви можете використовувати команду sql show global variables like 'innodb_buffer%';для перевірки розміру буфера.

Рішення - знайти свій my.cnfфайл і додати,

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

НЕ забудьте додати [mysqld], інакше це не спрацює.

У моєму випадку, Убунту 16.04 , my.cnfзнаходяться в папці /etc/mysql/.


4

Я запускаю вікна MySQL з робочим середовищем MySQL. Перейдіть до Сервер> Статус сервера Угорі там написано файл конфігурації: "шлях" (C:\ProgramData\MySQL\...\my.ini )

Потім у файлі "my.ini" натисніть control + F і знайдіть buffer_pool_size. Встановіть значення вище, я б рекомендував 64 МБ (за замовчуванням 8 МБ).

Перезапустіть сервер, перейшовши до Instance> Startup / Shutdown> Stop server (а потім пізніше запустіть сервер знову)

У моєму випадку я не міг видалити записи зі своєї таблиці.


2

Якщо ви правильно структурували свої таблиці так, щоб кожна містила відносно унікальні значення, то менш інтенсивним способом зробити це було б зробити 3 окремі оператори вставки, по 1 для кожної таблиці, з фільтром об'єднання на місці для кожної вставки -

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 може бути дорогим, оскільки спочатку він створює власну тимчасову таблицю для заповнення даних із трьох окремих джерел, перш ніж вставляти в таблицю, яку потрібно ВЖЕ, із запуском іншої під- запит для фільтрування результатів.


2

у windows: якщо у вас робочий стіл mysql. Перейдіть до статусу сервера. знайти місце запущеного файлу сервера в моєму випадку це було:

C:\ProgramData\MySQL\MySQL Server 5.7

відкрийте файл my.ini і знайдіть buffer_pool_size. Встановіть значення високим. значення за замовчуванням - 8 млн. Ось як я вирішив цю проблему


1

Фіксація коду помилки 1206: Кількість блокувань перевищує розмір таблиці блокування.

У моєму випадку я працюю з MySQL Workbench (5.6.17) під управлінням Windows під управлінням WampServer 2.5.

Для Windows / WampServer вам потрібно відредагувати файл my.ini (а не файл my.cnf)

Щоб знайти цей файл, перейдіть до меню Сервер / Статус сервера (у MySQL Workbench) і перегляньте розділ Каталоги серверів / Каталог бази

Сервер MySQL - стан сервера

У файлі my.ini є окремі розділи для різних налаштувань, шукайте розділ [mysqld] (створіть його, якщо він не існує) і додайте команду: innodb_buffer_pool_size = 4G

[mysqld]
innodb_buffer_pool_size = 4G

Розмір файлу buffer_pool залежатиме від вашої машини, у більшості випадків проблему вирішить 2G або 4G.

Не забудьте перезапустити сервер, щоб він зайняв нову конфігурацію, це вирішило проблему для мене.

Сподіваюся, це допоможе!


1

Те саме питання, яке я отримую у своєму MYSQL під час запуску скрипта sql. Будь ласка, зверніть увагу на зображення нижче. Код помилки 1206: Кількість блокувань перевищує розмір таблиці замків

Це проблема конфігурації Mysql, тому я вніс деякі зміни, my.ini і вона працює в моїй системі та вирішено проблему.

Нам потрібно внести деякі зміни, my.iniякі доступні на наступному шляху: - C:\ProgramData\MySQL\MySQL Server 5.7\my.ini і, будь ласка, оновіть такі зміни у my.iniполях конфігураційних файлів: -

key_buffer_size=64M
read_buffer_size=64M
read_rnd_buffer_size=128M
innodb_log_buffer_size=10M
innodb_buffer_pool_size=256M
query_cache_type=2
max_allowed_packet=16M

Після всіх вищезазначених змін перезапустіть службу MYSQL . Будь ласка, зверніться до зображення: - Microsoft MYSQL Service Picture


0

Варто сказати, що цифра, яка використовується для цього налаштування, у байтах - це з’ясувалося непростим шляхом!


2
Здається, це скоріше коментар, а не відповідь. Не могли б ви змінити це на коментар?
Бен Оот'єрс,

0

Ця відповідь нижче не відповідає безпосередньо на питання ОП. Однак я додаю цю відповідь сюди, оскільки ця сторінка є першим результатом, коли ви шукаєте в 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", якщо у вашій таблиці не вказана дата.

Сподіваюся, це комусь допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.