このようなテーブルがあります:
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;
そしてこのようなもの:
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;
そして、このようなSQLステートメント
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;
説明すると、これがわかります:
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| 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)
100万行の場合、これはかなり遅いです。私はproducts.nameにインデックスを追加しようとしました:
ALTER TABLE products ADD INDEX `product_name_idx` (name(512));
これはこれを与えます:
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)
このページ で説明されているように、Sub_part列にはインデックス付きのプレフィックスが表示されていると思います(バイト単位)。
クエリを再説明すると、次の結果が得られます。
+----+-------------+-------+------+----------------------------+----------------------------+---------+---------+--------+----------------+
| 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)
新しいインデックスは使用されていないようです。 このページ で説明されているように、インデックスがプレフィックスインデックスである場合、インデックスはソートに使用されません。実際、次のようにしてデータを切り捨てた場合:
alter table products modify `name` varchar(255) not null;
Explainは以下を提供します。
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
| 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 | |
+----+-------------+-------+-------+----------------------------+----------------------------+---------+----------------------------------------------+------+-------+
それを裏付けていると思います。ただし、 このページ では、InnoDBテーブルは最大767バイトのインデックスを持つことができると述べています。長さがバイト単位の場合、なぜ255を超えることを拒否するのですか?文字単位の場合、各UTF-8文字の長さはどのように決定されますか? 3だけを想定していますか?
また、このバージョンのMySQLを使用しています。
mysql> select version();
+------------+
| version() |
+------------+
| 5.5.27-log |
+------------+
1 row in set (0.00 sec)
InnoDBテーブルの制限
警告
MysqlデータベースのMySQLシステムテーブルをMyISAMからInnoDBテーブルに変換しないでください。これはサポートされていない操作です。これを行うと、バックアップから古いシステムテーブルを復元するか、mysql_install_dbプログラムでそれらを再生成するまで、MySQLは再起動しません。
警告
NFSボリューム上のデータファイルまたはログファイルを使用するようにInnoDBを構成することはお勧めできません。そうしないと、ファイルが他のプロセスによってロックされ、MySQLで使用できなくなる可能性があります。
最大値と最小値
Innodb_large_prefixが有効な場合、REDUNDANTまたはCOMPACTテーブルに対して3072を超えるキー長でインデックスプレフィックスを作成しようとすると、ER_INDEX_COLUMN_TOO_LONGエラーが発生します。
InnoDBの内部最大キー長は3500バイトですが、MySQL自体はこれを3072バイトに制限しています。この制限は、複数列インデックスの結合インデックスキーの長さに適用されます。
可変長列(VARBINARY、VARCHAR、BLOB、TEXT)を除く最大行長は、データベースページの半分よりわずかに短いです。つまり、最大行長は約8000バイトです。 LONGBLOBおよびLONGTEXT列は4GB未満である必要があり、BLOBおよびTEXT列を含む行の合計長は4GB未満である必要があります。
リファレンス: InnoDB Restrictions