Änderungslimit für "MySQL-Zeilengröße zu groß"


104

Wie kann ich das Limit ändern?

Zeilengröße zu groß (> 8126). Das Ändern einiger Spalten in TEXT oder BLOB oder das Verwenden von ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSEDkann hilfreich sein. Im aktuellen Zeilenformat wird das BLOBPräfix 768 Byte inline gespeichert.

Tabelle:

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
top_a   varchar(255)    No       
top_b   varchar(255)    No       
top_c   varchar(255)    No       
top_d   varchar(255)    No       
top_e   varchar(255)    No       
top_f   varchar(255)    No       
top_g   varchar(255)    No       
top_h   varchar(255)    No       
top_i   varchar(255)    No       
top_j   varchar(255)    No       
top_title_a varchar(255)    No       
top_title_b varchar(255)    No       
top_title_c varchar(255)    No       
top_title_d varchar(255)    No       
top_title_e varchar(255)    No       
top_title_f varchar(255)    No       
top_title_g varchar(255)    No       
top_title_h varchar(255)    No       
top_title_i varchar(255)    No       
top_title_j varchar(255)    No       
top_desc_a  text    No       
top_desc_b  text    No       
top_desc_c  text    No       
top_desc_d  text    No       
top_desc_e  text    No       
top_desc_f  text    No       
top_desc_g  text    No       
top_desc_h  text    No       
top_desc_i  text    No       
top_desc_j  text    No       
status  int(11) No       
admin_id    int(11) No 

1
Was wird Noangezeigt?
hjpotter92

Fehler "Zeilengröße zu groß (> 8126) kann nicht aktualisiert werden. Das Ändern einiger Spalten in TEXT oder BLOB oder die Verwendung von ROW_FORMAT = DYNAMIC oder ROW_FORMAT = COMPRESSED kann hilfreich sein. Im aktuellen Zeilenformat wird das BLOB-Präfix von 768 Byte inline gespeichert."
Lasha Kurt

Können Sie Ihrem Beitrag einige weitere Details hinzufügen, zumindest als Kommentar?
Eineki

1
Wenn sich diese Daten in einer anderen Tabelle befinden, sollten Sie stattdessen einen Fremdschlüssel verwenden. Dadurch wird die Zeilengröße drastisch verringert und das Datenbankschema normalisiert.
Didierc

1
@AL: Ups, Sie haben Recht - geben Sie eine enge Abstimmung über andere
Pathikrit

Antworten:


120

Die Frage wurde auch bei Serverfault gestellt .

Vielleicht möchten Sie sich diesen Artikel ansehen, in dem viel über die MySQL-Zeilengrößen erklärt wird. Es ist wichtig zu beachten, dass selbst wenn Sie TEXT- oder BLOB-Felder verwenden, Ihre Zeilengröße immer noch über 8 KB liegen kann (Limit für InnoDB), da die ersten 768 Bytes für jedes Feld inline auf der Seite gespeichert werden.

Der einfachste Weg, dies zu beheben, besteht darin, das Barracuda-Dateiformat mit InnoDB zu verwenden. Dies beseitigt das Problem im Grunde genommen insgesamt, indem nur der 20-Byte-Zeiger auf die Textdaten gespeichert wird, anstatt die ersten 768 Bytes zu speichern.


Die Methode, die für das OP dort funktionierte, war:

  1. Fügen Sie der my.cnfDatei unter [mysqld]Abschnitt Folgendes hinzu .

    innodb_file_per_table=1
    innodb_file_format = Barracuda
  2. ALTERdie zu verwendende Tabelle ROW_FORMAT=COMPRESSED.

    ALTER TABLE nombre_tabla
        ENGINE=InnoDB
        ROW_FORMAT=COMPRESSED 
        KEY_BLOCK_SIZE=8;

Es besteht die Möglichkeit, dass die oben genannten Probleme immer noch nicht behoben werden. Es ist ein bekannter (und verifizierter) Fehler mit der InnoDB- Engine, und eine vorübergehende Lösung besteht derzeit darin, auf die MyISAM- Engine als temporären Speicher zurückzugreifen. Also, in Ihrer my.cnfDatei:

internal_tmp_disk_storage_engine=MyISAM

12
+1 -> Der Teil innodb_file_per_table ist von entscheidender Bedeutung und geht Hand in Hand mit der Änderung des Formats in Barracuda. Ohne sie wird MySQL Antelope stillschweigend weiter verwenden.
Nick

1
@Eduardo Ich würde empfehlen, zuerst die Daten zu sichern. Aber ja, das können Sie auch in der Produktion!
hjpotter92

3
Verwenden Sie innodb_file_per_table=1diese Option, um diese Option zu aktivieren.
Stijn Geukens

2
Dies kann das Problem nicht garantiert beheben. In diesem Beitrag finden Sie ein Beispielskript, das diese Einstellungen hinzufügt, den Fehler jedoch weiterhin reproduzieren kann.
Cerin

1
@ user1183352 Meine Antwort oben wurde aktualisiert. Vielen Dank, dass Sie mich erneut daran erinnert haben, tiefer in dieses Thema einzutauchen. :)
hjpotter92

61

Ich bin kürzlich auf dieses Problem gestoßen und habe es auf andere Weise gelöst. Wenn Sie MySQL Version 5.6.20 ausführen, ist ein Fehler im System bekannt. Siehe MySQL-Dokumente

Wichtig Aufgrund des Fehlers Nr. 69477 können Redo-Log-Schreibvorgänge für große, extern gespeicherte BLOB-Felder den letzten Prüfpunkt überschreiben. Um diesen Fehler zu beheben, begrenzt ein in MySQL 5.6.20 eingeführter Patch die Größe der Redo-Log-BLOB-Schreibvorgänge auf 10% der Größe der Redo-Log-Datei. Aufgrund dieser Begrenzung sollte innodb_log_file_size auf einen Wert festgelegt werden, der größer ist als das Zehnfache der größten BLOB-Datengröße in den Zeilen Ihrer Tabellen zuzüglich der Länge anderer Felder variabler Länge (Felder vom Typ VARCHAR, VARBINARY und TEXT).

In meiner Situation war der beleidigende Blob-Tisch ungefähr 16 MB groß. Die Art und Weise, wie ich es gelöst habe, war das Hinzufügen einer Zeile zu my.cnf, die sicherstellte, dass ich mindestens das 10-fache dieses Betrags hatte und noch einige mehr:

innodb_log_file_size = 256M


Genau richtig. Mein Fehler "Zeilengröße zu groß" in einem longblobFeld verschwand, sobald ich den innodb_log_file_sizeParameter erhöhte . Lief auch 5.6.20.
Adamup

Vielen Dank. Wurde Homebrew 5.6.21 ausgeführt, wurde das Problem durch Ändern des Parameters behoben.
Nanoman

Sowohl diese als auch die Antwort von @ hjpotter92 waren erforderlich, um diesen Fehler für mich zu beheben.
Cerin

Vielen Dank. Lief 5.6.21 und diese Lösung half.
Petiar

Dies hat auch mein Problem nicht gelöst. Ich denke darüber nach, viele meiner VARCHAR-Felder durch TEXTs zu ersetzen, wie ich in ähnlichen Threads gesehen habe.
PDoria

28

Stellen Sie Folgendes in Ihrer my.cnf-Datei ein und starten Sie den MySQL-Server neu.

innodb_strict_mode=0

2
innodb_strict_mode=0-> keine Leerzeichen. Andernfalls führt ein Neustart von mariaDB 10.2 zu einem Fehler :-P
Pathros

Ich habe es nicht mit Mariadb versucht, für MySQL müssen keine Leerzeichen entfernt werden.
Karl

1
Entsprechend der Dokumentation verhindert das Deaktivieren des strengen Modus nur das Auftreten von Fehlern und Warnungen, sodass das Problem anscheinend nicht gelöst wird! download.nust.na/pub6/mysql/doc/innodb-plugin/1.1/en/…
João Teixeira

2
Dies scheint zu funktionieren und ich kann die Tabellen ohne Probleme erstellen und Daten speichern
Chris Muench

@ João, es macht mehr .. dev.mysql.com/doc/refman/8.0/en/…
Karl

24

Wenn Sie den ENGINE wechseln und MyISAM anstelle von InnoDB verwenden können, sollte dies helfen:

ENGINE=MyISAM

Es gibt zwei Einschränkungen bei MyISAM (wohl mehr):

  1. Sie können keine Transaktionen verwenden.
  2. Sie können keine Fremdschlüsseleinschränkungen verwenden.

5
Gut, wenn es Ihnen nichts ausmacht, auf Transaktionen und Fremdschlüsseleinschränkungen zu verzichten. Beachten Sie jedoch, dass Sie diese verlieren, wenn Sie zu MyISAM wechseln.
Wobbily_col

Dieser Rat ist verrückt - zumindest wird er alle Vorbehalte ausdrücken! Transaktionen und die wichtigsten Einschränkungen sind die geringsten Probleme bei diesem Format!
Hassan Syed

Entschuldigung, diese Antwort wurde abgelehnt. Bitte aktualisieren Sie, um alle damit verbundenen Einschränkungen zu erwähnen. Jeder, der nur diesen Rat befolgt, wechselt zu einem Format, das ich auf keinem Produktionssystem verwenden würde.
Remco Wendt

2
Und MyISAM geht weg.
Rick James

2
arbeitete für mich. In meinem Fall hatte ich über 300 Felder mit einer Länge von jeweils etwa 10. Ich habe keine Beziehungen in dieser Tabelle, daher war der Wechsel zu MyISAM die Lösung.
Robert Saylor

12

Ich möchte eine tolle Antwort teilen, es könnte hilfreich sein. Credits Bill Karwin siehe hier /dba/6598/innodb-create-table-error-row-size-too-large

Sie variieren je nach InnoDB-Dateiformat. Derzeit gibt es zwei Formate, Antelope und Barracuda.

Die zentrale Tablespace-Datei (ibdata1) ist immer im Antelope-Format. Wenn Sie Datei pro Tabelle verwenden, können Sie die einzelnen Dateien im Barracuda-Format verwenden, indem Sie in my.cnf innodb_file_format = Barracuda festlegen.

Grundlegende Punkte:

  1. Eine 16-KB-Seite mit InnoDB-Daten muss mindestens zwei Datenzeilen enthalten. Außerdem hat jede Seite eine Kopf- und Fußzeile mit Seitenprüfsummen, Protokollsequenznummer usw. Hier erhalten Sie ein Limit von etwas weniger als 8 KB pro Zeile.

  2. Datentypen mit fester Größe wie INTEGER, DATE, FLOAT, CHAR werden auf dieser primären Datenseite gespeichert und zählen zur Beschränkung der Zeilengröße.

  3. Datentypen mit variabler Größe wie VARCHAR, TEXT, BLOB werden auf Überlaufseiten gespeichert, sodass sie nicht vollständig für die Zeilengrößenbeschränkung angerechnet werden. In Antelope werden bis zu 768 Bytes solcher Spalten zusätzlich zur Überlaufseite auf der Primärdatenseite gespeichert. Barracuda unterstützt ein dynamisches Zeilenformat, sodass möglicherweise nur ein 20-Byte-Zeiger auf der Primärdatenseite gespeichert wird.

  4. Datentypen mit variabler Größe werden außerdem 1 oder mehr Bytes vorangestellt, um die Länge zu codieren. Das InnoDB-Zeilenformat verfügt auch über eine Reihe von Feldversätzen. Es gibt also eine interne Struktur, die mehr oder weniger in ihrem Wiki dokumentiert ist.

Barracuda unterstützt auch ROW_FORMAT = COMPRESSED, um die Speichereffizienz für Überlaufdaten zu erhöhen.

Ich muss auch kommentieren, dass ich noch nie gesehen habe, dass eine gut gestaltete Tabelle die Zeilengrößenbeschränkung überschreitet. Es ist ein starker "Code-Geruch", dass Sie gegen die Bedingung der sich wiederholenden Gruppen der ersten Normalform verstoßen.


7

Ich hatte das gleiche Problem, das löste es für mich:

ALTER TABLE `my_table` ROW_FORMAT=DYNAMIC;

Aus der MYSQL- Dokumentation :

Das Zeilenformat DYNAMIC behält die Effizienz bei, die gesamte Zeile im Indexknoten zu speichern, wenn es passt (wie auch die Formate COMPACT und REDUNDANT). Dieses neue Format vermeidet jedoch das Problem, B-Baumknoten mit einer großen Anzahl von Datenbytes von zu füllen lange Spalten. Das DYNAMIC-Format basiert auf der Idee, dass es normalerweise am effizientesten ist, den gesamten Wert außerhalb der Seite zu speichern, wenn ein Teil eines langen Datenwerts außerhalb der Seite gespeichert wird. Beim DYNAMIC-Format verbleiben wahrscheinlich kürzere Spalten im B-Tree-Knoten, wodurch die Anzahl der für eine bestimmte Zeile erforderlichen Überlaufseiten minimiert wird.


... aber du musst ein anderes Dateiformat haben, also bist du schon auf Barracuda? Weil ich einen Fehler bekomme, der diesen Befehl versucht und sagtWarnings from last query: InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope
Ted

Als ich HeidiSQL den gleichen Befehl über seine eingebaute GUI ausführen ließ, war es irgendwie erfolgreich, aber es half überhaupt nicht, ich bekomme den gleichen FehlerRow size too large (>8126)
Ted

Versuchen Sie, innodb_file_format = Barracuda in my.ini zu setzen und versuchen Sie ALTER TABLE my_tableROW_FORMAT = DYNAMIC; wieder
multimediaxp

Ja, ich denke, das habe ich am Ende tatsächlich getan, und ich denke, das hat es gelöst. Aber ich habe auch verzweifelt viele Spalten gleichzeitig in TEXT geändert =) Trotzdem denke ich, dass es das war.
Ted

Gut!, Wenn Sie der Meinung sind, dass dies eine gute Antwort ist, stimmen Sie ab und akzeptieren Sie sie als gültige Antwort, danke!
Multimediaxp

5

Nachdem ich Stunden verbracht habe, habe ich die Lösung gefunden: Führen Sie einfach die folgende SQL in Ihrem MySQL-Administrator aus, um die Tabelle in MyISAM zu konvertieren:

USE db_name;
ALTER TABLE table_name ENGINE=MYISAM;

Hilft nicht viel, wenn das Problem in einer Anweisung zum Erstellen einer Tabelle auftritt.
Mark Fraser

create tablehat die gleiche Option:CREATE TABLE ... ENGINE=MyISAM ...
Xebeche

3

Ich bin auf dieses Problem gestoßen, als ich versucht habe, eine gesicherte MySQL-Datenbank von einem anderen Server wiederherzustellen. Was dieses Problem für mich gelöst hat, war das Hinzufügen bestimmter Einstellungen zu my.conf (wie in den obigen Fragen) und das zusätzliche Ändern der SQL-Sicherungsdatei:

Schritt 1: Fügen Sie die folgenden Zeilen in my.conf hinzu oder bearbeiten Sie sie:

innodb_page_size=32K
innodb_file_format=Barracuda
innodb_file_per_table=1

Schritt 2 Fügen Sie ROW_FORMAT = DYNAMIC zur Anweisung create create in der SQL-Sicherungsdatei für die Tabelle hinzu, die diesen Fehler verursacht:

DROP TABLE IF EXISTS `problematic_table`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `problematic_table` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
  ...
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 ROW_FORMAT=DYNAMIC;

Die wichtige Änderung oben ist ROW_FORMAT = DYNAMIC. (das war nicht in der ursprünglichen SQL-Sicherungsdatei enthalten)

Quelle, die mir bei der Lösung dieses Problems geholfen hat: MariaDB und InnoDB MySQL Zeilengröße zu groß


1
Die in Schritt 1 beschriebenen Zeilen sollten kein Leerzeichen haben. Line innodb_page_size=32Kfunktionierte nicht, da es in meinem Fall zu einem Fehler beim Neustart von MariaDB 10.2 kam. Stattdessen habe ich innodb_strict_mode=0Zeile hinzugefügt , wie hier
Pathros

1
Vielen Dank für das Feedback Pathros, ich habe meine Antwort aktualisiert und die Leerzeichen aus Schritt 1 entfernt.
Matyas

Hinweis für MySQL <= 5.7.5: 32K ist keine gültige Option für innodb_page_size. Siehe: dev.mysql.com/doc/refman/5.6/en/…
Dub Nazar

Außerdem müssen Sie Ihren gesamten MySQL-Server für scracth neu erstellen, da das Ändern innodb_page_sizeeine ibdata*Neuerstellung erfordert , was eine destruktive Operation ist. Weitere Informationen finden Sie in Ihrem Syslog
Matija Nalis

2

Die anderen Antworten beziehen sich auf die gestellte Frage. Ich werde auf die zugrunde liegende Ursache eingehen: schlechtes Schemadesign.

Spreizen Sie ein Array nicht über Spalten. Hier haben Sie 3 * 10 Spalten, die in 10 Zeilen mit 3 Spalten in einer neuen Tabelle (plus idusw.) umgewandelt werden sollen.

Ihr MainTisch hätte nur

id  int(11) No       
name    text    No       
date    date    No       
time    time    No       
schedule    int(11) No       
category    int(11) No       
status  int(11) No       
admin_id    int(11) No 

Ihre zusätzliche Tabelle ( Top) hätte

id  int(11) No          -- for joining to Main
seq TINYINT UNSIGNED    -- containing 1..10
img   varchar(255)    No       
title varchar(255)    No       
desc  text    No    
PRIMARY KEY(id, seq)    -- so you can easily find the 10 top_titles

Es würde 10 sein (oder weniger? Oder mehr?) Zeilen Topfür jeden id.

Dies beseitigt Ihr ursprüngliches Problem und bereinigt das Schema. (Dies ist keine "Normalisierung", wie in einigen Kommentaren diskutiert.)

Wechseln Sie nicht zu MyISAM. es geht weg.
Mach dir keine Sorgen ROW_FORMAT.

Sie müssen Ihren Code ändern, um das zu tun JOINund mehrere Zeilen anstelle mehrerer Spalten zu verarbeiten.


1

Ich verwende MySQL 5.6 unter AWS RDS. Ich habe folgendes in der Parametergruppe aktualisiert.

innodb_file_per_table=1
innodb_file_format = Barracuda

Ich musste die DB-Instanz neu starten, damit Änderungen an Parametergruppen wirksam wurden.

Außerdem wurde ROW_FORMAT = COMPRESSED nicht unterstützt. Ich habe DYNAMIC wie unten verwendet und es hat gut funktioniert.

ALTER TABLE nombre_tabla ENGINE=InnoDB ROW_FORMAT=DYNAMIC KEY_BLOCK_SIZE=8

1

Die maximale Zeilengröße für eine InnoDB-Tabelle, die für lokal auf einer Datenbankseite gespeicherte Daten gilt, beträgt für 4 KB, 8 KB, 16 KB und 32 KB etwas weniger als eine halbe Seite

Für 16-KB-Seiten (Standard) können wir Folgendes berechnen:

Slightly less than half a page 8126 / Number of bytes to threshold for overflow 767 = 10.59 fields of 767 bytes maximum

Grundsätzlich können Sie eine Reihe maximal nutzen mit:

  • 11 Varchar-Felder> 767 Zeichen (latin1 = 1 Byte pro Zeichen) oder
  • 11 Varchar-Felder> 255 Zeichen (utf-8 auf MySQL = 3 Bytes pro Zeichen).

Denken Sie daran, dass eine Überlaufseite nur dann überläuft, wenn das Feld> 767 Byte ist. Wenn zu viele Felder mit 767 Bytes vorhanden sind, wird es kaputt gehen (über max row_size hinaus). Nicht üblich mit latin1, aber sehr gut möglich mit utf-8, wenn die Entwickler nicht vorsichtig sind.

In diesem Fall könnten Sie möglicherweise die innodb_page_size auf 32 KB erhöhen.

in my.cnf:

innodb_page_size=32K

Verweise:


0

Ich bin auch auf das gleiche Problem gestoßen. Ich löse das Problem, indem ich die folgende SQL ausführe:

ALTER ${table} ROW_FORMAT=COMPRESSED;

Aber ich denke, du solltest etwas über den Zeilenspeicher wissen .
Es gibt zwei Arten von Spalten: Spalten mit variabler Länge (z. B. VARCHAR-, VARBINARY-, BLOB- und TEXT-Typen) und Spalten mit fester Länge . Sie werden auf verschiedenen Seitentypen gespeichert.

Ausnahmen von dieser Regel sind Spalten mit variabler Länge. Spalten wie BLOB und VARCHAR, die zu lang sind, um auf eine B-Tree-Seite zu passen, werden auf separat zugewiesenen Festplattenseiten gespeichert, die als Überlaufseiten bezeichnet werden. Wir nennen solche Spalten Off-Page-Spalten. Die Werte dieser Spalten werden in einfach verknüpften Listen von Überlaufseiten gespeichert, und jede dieser Spalten verfügt über eine eigene Liste von einer oder mehreren Überlaufseiten. In einigen Fällen wird der gesamte oder ein Präfix des langen Spaltenwerts im B-Baum gespeichert, um Speicherverschwendung zu vermeiden und das Lesen einer separaten Seite zu vermeiden.

und wenn der Zweck der Einstellung von ROW_FORMAT ist

Wenn eine Tabelle mit ROW_FORMAT = DYNAMIC oder ROW_FORMAT = COMPRESSED erstellt wird, kann InnoDB lange Spaltenwerte variabler Länge (für VARCHAR-, VARBINARY- sowie BLOB- und TEXT-Typen) vollständig außerhalb der Seite speichern, wobei der Clustered-Indexdatensatz nur einen 20- enthält Bytezeiger auf die Überlaufseite.

Möchten Sie mehr über die Zeilenformate DYNAMIC und COMPRESSED erfahren?


0

Wenn dies bei einem SELECT mit vielen Spalten auftritt, kann dies daran liegen, dass MySQL eine temporäre Tabelle erstellt. Wenn diese Tabelle zu groß ist, um in den Speicher zu passen, verwendet sie das Standardformat für temporäre Tabellen, InnoDB, um sie auf der Festplatte zu speichern. In diesem Fall gelten die Größenbeschränkungen für InnoDB.

Sie haben dann 4 Möglichkeiten:

  1. Ändern Sie die Beschränkung der Innodb-Zeilengröße wie in einem anderen Beitrag angegeben. Dies erfordert eine Neuinitialisierung des Servers.
  2. Ändern Sie Ihre Abfrage so, dass sie weniger Spalten enthält, oder vermeiden Sie, dass eine temporäre Tabelle erstellt wird (indem Sie die Klauseln order by und limit entfernen).
  3. Ändern von max_heap_table_size so dass das Ergebnis passt im Speicher groß sein und muss nicht auf die Platte geschrieben werden.
  4. Ändern Sie das Standardformat für temporäre Tabellen in MYISAM. Dies habe ich getan. Änderung in my.cnf:

    internal_tmp_disk_storage_engine=MYISAM

Starten Sie MySQL neu, die Abfrage funktioniert.


0

Hier ist ein einfacher Tipp für alle Interessierten:

Nach dem Upgrade von Debian 9 auf Debian 10 mit 10.3.17-MariaDB habe ich einige Fehler in Joomla-Datenbanken:

[Warnung] InnoDB: Feld fieldin Tabelle kann nicht hinzugefügt werden database.tableda nach dem Hinzufügen die Zeilengröße 8742 beträgt, was größer ist als die maximal zulässige Größe (8126) für einen Datensatz auf der Indexblattseite.

Nur für den Fall, ich habe innodb_default_row_format = DYNAMIC in /etc/mysql/mariadb.conf.d/50-server.cnf gesetzt (es war sowieso Standard)

Dann habe ich phpmyadmin verwendet, um "Tabelle optimieren" für alle Tabellen in der Joomla-Datenbank auszuführen. Ich denke, die von phpmyadmin durchgeführte Tabellenerholung hat dabei geholfen. Wenn Sie phpmyadmin installiert haben, sind es nur wenige Klicks.


Wenn Sie ein Joomla-Benutzer sind, besuchen Sie uns bei Joomla Stack Exchange - wir können immer neue Mitwirkende verwenden.
Mickmackusa
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.