J'ai une table comme celle-ci:
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;
et un comme ça:
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;
et une instruction SQL comme celle-ci
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;
qui si je l'explique me donne ceci:
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| 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)
Pour un million de lignes, c'est assez lent. J'ai essayé d'ajouter un index sur products.name avec:
ALTER TABLE products ADD INDEX `product_name_idx` (name(512));
ce qui donne ceci:
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)
Je pense que la colonne Sub_part montre le préfixe qui a été indexé (en octets), comme décrit sur cette page .
Lorsque je ré-explique la requête, j'obtiens:
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| 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)
qui semble que le nouvel index n'est pas utilisé. Comme décrit sur cette page , les index ne seront pas utilisés pour le tri s'ils sont des index préfixés. En fait, si je tronque les données avec:
alter table products modify `name` varchar(255) not null;
L'explication donne:
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
| 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 | |
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
qui, je pense, le confirme. Cependant, il est indiqué sur cette page que les tables InnoDB peuvent avoir jusqu'à 767 octets d'index. Si la longueur est en octets, pourquoi refuse-t-elle d'en avoir plus de 255? Si c'est en caractères, comment décide-t-il de la longueur de chaque caractère UTF-8? Est-ce juste en supposant 3?
J'utilise également cette version de MySQL:
mysql> select version();
+------------+
| version() |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)
Limites des tables InnoDB
Avertissement
Ne convertissez pas les tables système MySQL de la base de données mysql de MyISAM en tables InnoDB. Il s'agit d'une opération non prise en charge. Dans ce cas, MySQL ne redémarre pas tant que vous n'avez pas restauré les anciennes tables système à partir d'une sauvegarde ou que vous ne les régénérez pas avec le programme mysql_install_db.
Avertissement
Ce n'est pas une bonne idée de configurer InnoDB pour utiliser des fichiers de données ou des fichiers journaux sur des volumes NFS. Sinon, les fichiers pourraient être verrouillés par d'autres processus et devenir indisponibles pour MySQL.
Maximums et minimums
Lorsque innodb_large_prefix est activé, la tentative de création d'un préfixe d'index avec une longueur de clé supérieure à 3072 pour une table REDUNDANT ou COMPACT provoque une erreur ER_INDEX_COLUMN_TOO_LONG.
La longueur de clé maximale interne InnoDB est de 3500 octets, mais MySQL lui-même le limite à 3072 octets. Cette limite s'applique à la longueur de la clé d'index combinée dans un index à plusieurs colonnes.
La longueur maximale des lignes, à l'exception des colonnes de longueur variable (VARBINARY, VARCHAR, BLOB et TEXT), est légèrement inférieure à la moitié d'une page de base de données. Autrement dit, la longueur de ligne maximale est d'environ 8 000 octets. Les colonnes LONGBLOB et LONGTEXT doivent être inférieures à 4 Go et la longueur totale des lignes, y compris les colonnes BLOB et TEXT, doit être inférieure à 4 Go.
Référence: Restrictions InnoDB