it-swarm.com.de

MySQL-Varchar-Indexlänge

Ich habe einen Tisch wie diesen:

CREATE TABLE `products` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(512) NOT NULL,
  `description` text,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB AUTO_INCREMENT=38 DEFAULT CHARSET=utf8;

und eine davon:

CREATE TABLE `product_variants` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `product_id` int(11) unsigned NOT NULL,
  `product_code` varchar(255) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `product_code` (`product_code`),
  KEY `product_variant_product_fk` (`product_id`),
  CONSTRAINT `product_variant_product_fk` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1037 DEFAULT CHARSET=utf8;

und eine SQL-Anweisung wie diese

SELECT p.id AS id, p.name AS name, p.description AS description, pv.id AS product_variant_id, pv.product_code AS product_code
FROM products p
INNER JOIN product_variants pv ON pv.product_id = p.id
ORDER BY p.name ASC
LIMIT 300 OFFSET 0;

was, wenn ich es erkläre:

+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| id | select_type | table | type | possible_keys              | key                        | key_len | ref     | rows   | Extra          |
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
|  1 | SIMPLE      | p     | ALL  | PRIMARY                    | NULL                       | NULL    | NULL    | 993658 | Using filesort |
|  1 | SIMPLE      | pv    | ref  | product_variant_product_fk | product_variant_product_fk | 4       | db.p.id |      1 |                |
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
2 rows in set (0.00 sec)

Für eine Million Zeilen ist dies ziemlich langsam. Ich habe versucht, einen Index für products.name hinzuzufügen mit:

ALTER TABLE products ADD INDEX `product_name_idx` (name(512));

was das gibt:

mysql> show indexes from products;
+----------+------------+------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name         | Seq_in_index | Column_name     | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| products |          0 | PRIMARY          |            1 | id              | A         |      993658 |     NULL | NULL   |      | BTREE      |         |               |
| products |          1 | product_manf_fk  |            1 | manufacturer_id | A         |          18 |     NULL | NULL   | YES  | BTREE      |         |               |
| products |          1 | product_name_idx |            1 | name            | A         |         201 |      255 | NULL   |      | BTREE      |         |               |
+----------+------------+------------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)

Ich denke, dass die Sub_part-Spalte das Präfix zeigt, das indiziert wurde (in Bytes), wie auf diese Seite beschrieben.

Wenn ich die Abfrage erneut erkläre, erhalte ich Folgendes:

+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| id | select_type | table | type | possible_keys              | key                        | key_len | ref     | rows   | Extra          |
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
|  1 | SIMPLE      | p     | ALL  | PRIMARY                    | NULL                       | NULL    | NULL    | 993658 | Using filesort |
|  1 | SIMPLE      | pv    | ref  | product_variant_product_fk | product_variant_product_fk | 4       | db.p.id |      1 |                |
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
2 rows in set (0.00 sec)

das sieht so aus, als würde der neue Index nicht verwendet. Wie unter diese Seite beschrieben, werden Indizes nicht zum Sortieren verwendet, wenn es sich um Präfixindizes handelt. In der Tat, wenn ich die Daten mit abschneide:

alter table products modify `name`  varchar(255) not null;

Die Erklärung gibt:

+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
| id | select_type | table | type  | possible_keys              | key                        | key_len | ref                                          | rows | Extra |
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
|  1 | SIMPLE      | p     | index | PRIMARY                    | product_name_idx           | 767     | NULL                                         |  300 |       |
|  1 | SIMPLE      | pv    | ref   | product_variant_product_fk | product_variant_product_fk | 4       | oh_2c98c233_69fe_4f06_ad0d_fe6f85a5beac.p.id |    1 |       |
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+

was ich denke, unterstützt das. Es heißt jedoch am diese Seite , dass InnoDB-Tabellen bis zu 767 Byte Index haben können. Wenn die Länge in Bytes ist, warum lehnt es ab, mehr als 255 zu haben? Wie wird die Länge jedes UTF-8-Zeichens bestimmt, wenn es sich um Zeichen handelt? Geht man nur von 3 aus?

Ich verwende auch diese Version von MySQL:

mysql> select version();
+------------+
| version()  |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)
31
l0st3d

Grenzen für InnoDB-Tabellen

Warnung

Konvertieren Sie keine MySQL-Systemtabellen in der mysql-Datenbank von MyISAM zu InnoDB-Tabellen. Dies ist eine nicht unterstützte Operation. In diesem Fall wird MySQL erst neu gestartet, wenn Sie die alten Systemtabellen aus einer Sicherung wiederhergestellt oder mit dem Programm mysql_install_db neu generiert haben.

Warnung

Es ist keine gute Idee, InnoDB für die Verwendung von Datendateien oder Protokolldateien auf NFS-Volumes zu konfigurieren. Andernfalls werden die Dateien möglicherweise von anderen Prozessen gesperrt und können von MySQL nicht mehr verwendet werden.

Maxima und Minima

  1. Eine Tabelle kann maximal 1000 Spalten enthalten.
  2. Eine Tabelle kann maximal 64 Sekundärindizes enthalten.
  3. Standardmäßig kann ein Indexschlüssel für einen einspaltigen Index bis zu 767 Byte umfassen. Die gleiche Längenbeschränkung gilt für alle Indexschlüsselpräfixe. Beispielsweise können Sie dieses Limit mit einem Spaltenpräfixindex von mehr als 255 Zeichen in einer TEXT- oder VARCHAR-Spalte erreichen, wenn Sie einen UTF-8-Zeichensatz und maximal 3 Byte für jedes Zeichen annehmen. Wenn die Konfigurationsoption innodb_large_prefix aktiviert ist, wird diese Längenbeschränkung für InnoDB-Tabellen, die die Zeilenformate DYNAMIC und COMPRESSED verwenden, auf 3072 Byte erhöht.
  4. Wenn Sie eine Indexpräfixlänge angeben, die größer als der zulässige Maximalwert ist, wird die Länge automatisch auf die maximale Länge reduziert. In MySQL 5.6 und höher führt die Angabe einer Indexpräfixlänge, die größer als die maximale Länge ist, zu einem Fehler.

Wenn innodb_large_prefix aktiviert ist, führt der Versuch, ein Indexpräfix mit einer Schlüssellänge von mehr als 3072 für eine REDUNDANT- oder COMPACT-Tabelle zu erstellen, zu einem ER_INDEX_COLUMN_TOO_LONG-Fehler.

Die interne maximale Schlüssellänge von InnoDB beträgt 3500 Byte, aber MySQL selbst beschränkt diese auf 3072 Byte. Diese Begrenzung gilt für die Länge des kombinierten Indexschlüssels in einem mehrspaltigen Index.

Die maximale Zeilenlänge mit Ausnahme von Spalten variabler Länge (VARBINARY, VARCHAR, BLOB und TEXT) beträgt etwas weniger als die Hälfte einer Datenbankseite. Das heißt, die maximale Zeilenlänge beträgt ungefähr 8000 Bytes. LONGBLOB- und LONGTEXT-Spalten müssen kleiner als 4 GB sein, und die Gesamtzeilenlänge einschließlich BLOB- und TEXT-Spalten muss kleiner als 4 GB sein.

Referenz: InnoDB-Einschränkungen

1
Rads