Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Durchschnittliche Zeilenlänge höher als möglich

  • Weil avg_row_length ist data_length / rows .

data_length ist im Grunde die Gesamtgröße der Tabelle auf der Festplatte . Eine InnoDB-Tabelle ist mehr als nur eine Liste von Zeilen. Da ist also dieser zusätzliche Overhead.

  • Weil eine InnoDB-Zeile mehr ist als die Daten.

Ähnlich wie oben bringt jede Zeile etwas Overhead mit sich. Das wird also die Größe einer Reihe erhöhen. Eine InnoDB-Tabelle ist auch nicht nur eine zusammengepferchte Liste von Daten. Es braucht etwas zusätzlichen freien Platz, um effizient zu arbeiten.

  • Weil Dinge auf Festplatten in Blöcken gespeichert werden und diese Blöcke nicht immer voll sind.

Festplatten speichern Dinge normalerweise in 4K-, 8K- oder 16K-Blöcken . Manchmal passen Dinge nicht perfekt in diese Blöcke, sodass Sie einige leer bekommen können Leerzeichen .

Wie wir weiter unten sehen werden, weist MySQL die Tabelle in Blöcken zu. Und es wird viel mehr zuweisen, als es braucht, um zu vermeiden, dass der Tisch wachsen muss (was langsam sein kann und zu Festplattenfragmentierung was die Sache noch langsamer macht).

Beginnen wir zur Veranschaulichung mit einer leeren Tabelle.

mysql> create table foo ( id smallint(5) unsigned NOT NULL );
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          0 |              0 |
+-------------+------------+----------------+

Es verwendet 16K oder vier 4K-Blöcke, um nichts zu speichern. Die leere Tabelle benötigt diesen Platz nicht, aber MySQL hat ihn unter der Annahme zugewiesen, dass Sie eine Menge Daten darin ablegen werden. Dies vermeidet eine teure Neuzuweisung bei jeder Einfügung.

Jetzt fügen wir eine Zeile hinzu.

mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          1 |          16384 |
+-------------+------------+----------------+

Der Tisch wurde nicht größer, es gibt all diesen ungenutzten Platz in diesen 4 Blöcken, die er hat. Es gibt eine Zeile, was eine avg_row_length von 16 KB bedeutet. Eindeutig absurd. Lassen Sie uns eine weitere Zeile hinzufügen.

mysql> insert into foo (id) VALUES (1);
mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |          2 |           8192 |
+-------------+------------+----------------+

Gleiche Sache. 16 KB werden für die Tabelle zugewiesen, 2 Zeilen verwenden diesen Platz. Ein absurdes Ergebnis von 8K pro Zeile.

Wenn ich immer mehr Zeilen einfüge, bleibt die Tabellengröße gleich, sie verbraucht immer mehr des zugewiesenen Speicherplatzes und der avg_row_length kommt der Realität näher.

mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';                                                                     
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       16384 |       2047 |              8 |
+-------------+------------+----------------+

Auch hier beginnen wir, table_rows zu sehen ungenau werden. Ich habe definitiv 2048 Zeilen eingefügt.

Wenn ich jetzt etwas mehr einfüge...

mysql> select data_length, table_rows, avg_row_length from information_schema.tables where table_name = 'foo';
+-------------+------------+----------------+
| data_length | table_rows | avg_row_length |
+-------------+------------+----------------+
|       98304 |       2560 |             38 |
+-------------+------------+----------------+

(Ich habe 512 Zeilen eingefügt und table_rows aus irgendeinem Grund in die Realität zurückgekehrt ist)

MySQL hat entschieden, dass die Tabelle mehr Speicherplatz benötigt, also wurde sie in der Größe geändert und nahm einen Haufen mehr Speicherplatz ein. avg_row_length bin gerade wieder gesprungen.

Es hat viel mehr Platz beansprucht, als es für diese 512 Zeilen benötigt, jetzt sind es 96K oder 24 4K-Blöcke, in der Annahme, dass es später benötigt wird. Dadurch wird die Anzahl potenziell langsamer Neuzuweisungen minimiert und die Festplattenfragmentierung minimiert.

Das bedeutet nicht, dass der gesamte Platz ausgefüllt wurde . Es bedeutet nur, dass MySQL dachte, es sei voll genug, um mehr Platz zu benötigen, um effizient zu laufen. Wenn Sie wissen möchten, warum das so ist, sehen Sie sich an, wie eine Hash-Tabelle funktioniert arbeitet. Ich weiß nicht, ob InnoDB eine Hash-Tabelle verwendet, aber das Prinzip gilt:Einige Datenstrukturen funktionieren am besten, wenn es etwas leeren Platz gibt.

Die von einer Tabelle verwendete Festplatte steht in direktem Zusammenhang mit der Anzahl der Zeilen und Spaltentypen in der Tabelle, aber die genaue Formel ist schwer herauszufinden und ändert sich von Version zu Version von MySQL. Am besten führen Sie einige empirische Tests durch und geben sich damit ab, dass Sie niemals eine genaue Zahl erhalten werden.