Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle

75

Ich führe einen Bericht in MySQL aus. Bei einer der Abfragen wird eine große Anzahl von Zeilen in eine temporäre Tabelle eingefügt. Wenn ich versuche, es auszuführen, wird folgende Fehlermeldung angezeigt:

Fehlercode 1206: Die Anzahl der Sperren überschreitet die Größe der Sperrtabelle.

Die fraglichen Fragen sind:

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;

Ich habe gelesen, dass das Ändern der Konfigurationsdatei zum Erhöhen der Pufferpoolgröße hilfreich ist, aber das bringt nichts. Wie kann dies behoben werden, entweder als vorübergehende Problemumgehung oder als dauerhafte Lösung?

BEARBEITEN: Teil der Abfrage geändert. Sollte es nicht beeinflussen, aber ich habe alles gefunden und ersetzt und nicht bemerkt, dass es das vermasselt hat. Betrifft die Frage nicht.

EDIT 2: Typedesc zu t1 hinzugefügt. Ich habe es in der Abfrage geändert, aber nicht hier.

maxman92
quelle
Warum gruppieren Sie in den Unterauswahlen?
Tim
Ich finde das schwer zu verstehen. Wenn t2.customernum = t1.customer ist, ist es nicht sinnvoll, nur customernum aus topThreetransit auszuwählen. Sicherlich ist SkusBought.typedesc dann der gleiche Kundencode wie die erste Spalte?
RedGrittyBrick
t2 ist eine Teilmenge von Kunden in t1. Der Join besteht darin, Kunden in t1 loszuwerden, die nicht in t2 sind. Der Code für typedesc ist tatsächlich falsch. Auch hier wurde es im eigentlichen SQL-Skript geändert, aber nicht hier. Typedesc ist eine weitere Spalte mit Transaktionsdaten (alle drei). Ich werde es ändern, damit es richtig ist und es sinnvoller ist.
Maxman92
Ich schrieb eine skurrile Darstellung eines weit verbreitetes Problem bis hier
Drew
Mögliches Duplikat von "Die Gesamtzahl der Sperren überschreitet die Größe der
Sperrtabelle

Antworten:

63

Dieses Problem kann behoben werden, indem die höheren Werte für die MySQL-Variable festgelegt werden innodb_buffer_pool_size. Der Standardwert für innodb_buffer_pool_sizeist 8,388,608.

Informationen zum Ändern des Einstellungswerts für finden innodb_buffer_pool_sizeSie im folgenden Satz.

  1. Suchen Sie die Datei my.cnfvom Server. Bei Linux-Servern ist dies meistens der Fall/etc/my.cnf
  2. Fügen Sie die Zeile innodb_buffer_pool_size=64MBzu dieser Datei hinzu
  3. Starten Sie den MySQL-Server neu

Um den MySQL-Server neu zu starten, können Sie eine der folgenden 2 Optionen verwenden:

  1. Service mysqld Neustart
  2. /etc/init.d/mysqld Neustart

Referenz Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle

PHP-Fehler
quelle
1
Der Trick besteht darin, die richtige my.cnf-Datei zu finden und zu ändern. Auf meinem Mac befinden sich mindestens 20 Dateien mit diesem Namen, die aus früheren Versionen, dem Betriebssystem usw. veraltet sind. Die my.cnf-Datei, die bei mir funktioniert hat, war wie vorgeschlagen: /usr/local/mysql-5.6.23-osx10. 8-x86_64 / my.cnf
Toren
4
in Wamp ist my.ini
Enrique
Beachten Sie, dass das Minimum heutzutage 128 MB beträgt, sodass 64 MB nicht funktionieren. Sie müssen etwas Größeres als 128 MB angeben
Noam Rathaus
2
Unter MySQL 5.7.5 können Sie einfach ausführen, SET GLOBAL innodb_buffer_pool_size=268435456;ohne die Datei my.cnf zu durchsuchen und mysql neu zu starten. stackoverflow.com/a/38333056/3553564
Klim
23

Ich habe einen anderen Weg gefunden, um es zu lösen - benutze Table Lock. Sicher, es kann für Ihre Anwendung ungeeignet sein - wenn Sie die Tabelle gleichzeitig aktualisieren müssen.

Siehe: Versuchen Sie LOCK TABLES, die gesamte Tabelle anstelle der Standardaktion der MVCC-Sperre auf Zeilenebene von InnoDB zu sperren. Wenn ich mich nicht irre, bezieht sich die "Sperrtabelle" auf die interne InnoDB-Struktur, in der Zeilen- und Versionskennungen für die MVCC-Implementierung gespeichert sind, wobei ein Bit, das die Zeile identifiziert, in einer Anweisung geändert wird, und eine Tabelle mit 60 Millionen Zeilen. überschreitet wahrscheinlich den ihm zugewiesenen Speicher. Der LOCK TABLESBefehl sollte dieses Problem beheben, indem anstelle einer Zeilenebene eine Sperre auf Tabellenebene festgelegt wird:

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, Community Relations Manager, Nordamerika, MySQL Inc.

Michael Goltsman
quelle
Ich habe die Anweisungen in dieser Antwort befolgt und überhaupt keine Verbesserung festgestellt. Ich verwende Version 5.6.
mbmast
7
Diese Lösung hat auch bei mir mit MySQL 5.1 nicht funktioniert. Vielleicht funktioniert das bei neueren Versionen nicht mehr?
Frankreich
1
In meinem Fall war die Isolationsstufe nicht wichtig und ich habe sie in READ UNCOMMITED geändert. Damit war das Problem mit den Schlössern behoben. Dies hängt jedoch von Ihrem Anwendungsfall ab. SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
Itstata
14

Aus der MySQL-Dokumentation (die Sie bereits gelesen haben, wie ich sehe):

1206 (ER_LOCK_TABLE_FULL)

Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle. Um diesen Fehler zu vermeiden, erhöhen Sie den Wert von innodb_buffer_pool_size. Innerhalb einer einzelnen Anwendung kann eine Problemumgehung darin bestehen, einen großen Vorgang in kleinere Teile zu zerlegen. Wenn der Fehler beispielsweise bei einem großen INSERT auftritt, führen Sie mehrere kleinere INSERT-Operationen aus.

Wenn das Erhöhen von innodb_buffer_pool_size nicht hilft, folgen Sie einfach den Angaben auf dem fettgedruckten Teil und teilen Sie Ihren INSERT in 3 auf. Überspringen Sie die UNIONs und erstellen Sie 3 INSERTs mit jeweils einem JOIN zur topThreetransit- Tabelle.

MicSim
quelle
5

Zunächst können Sie den Befehl sql verwenden show global variables like 'innodb_buffer%';, um die Puffergröße zu überprüfen.

Lösung ist Ihre my.cnfDatei zu finden und hinzuzufügen,

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

NICHT vergessen hinzuzufügen [mysqld], sonst wird es nicht funktionieren.

In meinem Fall ubuntu 16.04 , my.cnfwird unter dem Ordner befindet /etc/mysql/.

Brad
quelle
4

Ich führe MySQL Windows mit MySQL Workbench aus. Gehen Sie zu Server> Serverstatus. Oben steht die Konfigurationsdatei: "path" ( C:\ProgramData\MySQL\...\my.ini)

Dann drücken Sie in der Datei "my.ini" Strg + F und suchen buffer_pool_size. Stellen Sie den Wert höher ein, ich würde 64 MB empfehlen (Standard ist 8 MB).

Starten Sie den Server neu, indem Sie zu Instanz> Start / Herunterfahren> Server stoppen gehen (und den Server später erneut starten).

In meinem Fall konnte ich keine Einträge aus meiner Tabelle löschen.

Dejoma
quelle
2

Wenn Sie Ihre Tabellen so strukturiert haben, dass jede relativ eindeutige Werte enthält, besteht die weniger intensive Methode darin, drei separate Insert-In-Anweisungen auszuführen, eine für jede Tabelle, wobei der Join-Filter für jede Einfügung vorhanden ist.

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

Wiederholen Sie diesen Vorgang für die beiden anderen Tabellen. Kopieren / Einfügen ist eine gute Methode. Ändern Sie einfach den Namen der FROM-Tabelle. ** Wenn Sie versuchen, doppelte Einträge in Ihrer SkusBought-Tabelle zu verhindern, können Sie vor der WHERE-Klausel in jedem Abschnitt den folgenden Join-Code hinzufügen.

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

-und dann die letzte Zeile der WHERE-Klausel-

AND t3.customer IS NULL

Ihr anfänglicher Code verwendet eine Reihe von Unterabfragen, und die UNION-Anweisung kann teuer sein, da sie zuerst eine eigene temporäre Tabelle erstellt, um die Daten aus den drei separaten Quellen zu füllen, bevor sie in die gewünschte Tabelle eingefügt wird, während eine andere Unterabfrage ausgeführt wird Abfrage zum Filtern der Ergebnisse.

Forrest Pugh
quelle
2

in Windows: Wenn Sie MySQL Workbench haben. Wechseln Sie zum Serverstatus. Finden Sie den Speicherort der laufenden Serverdatei in meinem Fall:

C:\ProgramData\MySQL\MySQL Server 5.7

Öffnen Sie die Datei my.ini und suchen Sie die buffer_pool_size. Stellen Sie den Wert hoch ein. Der Standardwert ist 8M. So habe ich dieses Problem behoben

Ch HaXam
quelle
1

Behebung des Fehlercodes 1206: Die Anzahl der Sperren überschreitet die Größe der Sperrtabelle.

In meinem Fall arbeite ich mit MySQL Workbench (5.6.17), das unter Windows mit WampServer 2.5 ausgeführt wird.

Für Windows / WampServer müssen Sie die Datei my.ini bearbeiten (nicht die Datei my.cnf).

Um diese Datei zu finden, gehen Sie zu Menü Server / Server Status (in MySQL Workbench) und suchen Sie unter Serververzeichnisse / Basisverzeichnis

MySQL Server - Serverstatus

In der Datei my.ini sind Abschnitte für verschiedene Einstellungen definiert. Suchen Sie nach Abschnitt [mysqld] (erstellen Sie ihn, falls er nicht vorhanden ist) und fügen Sie den folgenden Befehl hinzu: innodb_buffer_pool_size = 4G

[mysqld]
innodb_buffer_pool_size = 4G

Die Größe der Datei buffer_pool hängt von Ihrem Computer ab. In den meisten Fällen wird das Problem durch 2G oder 4G behoben.

Denken Sie daran, den Server neu zu starten, damit die neue Konfiguration übernommen wird. Das Problem wurde für mich behoben.

Ich hoffe es hilft!

Efrain Plaza
quelle
0

Es ist erwähnenswert, dass die für diese Einstellung verwendete Zahl in BYTES angegeben ist - das haben wir auf die harte Tour herausgefunden!

Antonius
quelle
2
Dies scheint eher ein Kommentar als eine Antwort zu sein. Könnten Sie dies in einen Kommentar ändern?
Ben Ootjers
0

Diese Antwort unten beantwortet die Frage des OP nicht direkt. Ich füge diese Antwort hier hinzu, da diese Seite das erste Ergebnis ist, wenn Sie Google "Die Gesamtzahl der Sperren überschreitet die Größe der Sperrtabelle".


Wenn die von Ihnen ausgeführte Abfrage eine gesamte Tabelle analysiert, die Millionen von Zeilen umfasst, können Sie eine while-Schleife versuchen, anstatt die Grenzwerte in der Konfiguration zu ändern.

Der while-Look wird es in Stücke zerbrechen. Unten sehen Sie ein Beispiel für eine Schleife über eine indizierte Spalte mit dem Namen 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;

Sie können es auch so anpassen, dass es die Spalte "num" durchläuft, wenn Ihre Tabelle kein Datum verwendet.

Hoffe das hilft jemandem!

Joseph Shih
quelle
0

Gleiches Problem, das ich beim Ausführen des SQL-Skripts in meinem MYSQL bekomme. Sehen Sie sich das folgende Bild an. Fehlercode 1206: Die Anzahl der Sperren überschreitet die Größe der Sperrtabelle

Dies ist ein MySQL-Konfigurationsproblem, daher habe ich einige Änderungen vorgenommen my.ini und es funktioniert auf meinem System und das Problem wurde behoben.

Wir müssen einige Änderungen vornehmen, my.inidie unter folgendem Pfad verfügbar sind : -C:\ProgramData\MySQL\MySQL Server 5.7\my.ini und bitte aktualisieren Sie die folgenden Änderungen in den my.iniFeldern der Konfigurationsdatei: -

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

Nach allen oben genannten Änderungen starten Sie bitte den MYSQL-Dienst neu . Bitte beziehen Sie sich auf das Bild: - Microsoft MYSQL Service Picture

DhanRaj Wanjare
quelle