这是我的SQL表,一个大约6kk行的大表。
CREATE TABLE `slots` (
`id` mediumint(8) UNSIGNED NOT NULL,
`uid` smallint(5) UNSIGNED NOT NULL,
`music_id` mediumint(8) UNSIGNED NOT NULL,
`finished` int(10) UNSIGNED NOT NULL DEFAULT '0',
`completed` tinyint(1) UNSIGNED NOT NULL DEFAULT '0',
`hidden` tinyint(1) UNSIGNED NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `slots`
ADD PRIMARY KEY (`id`),
ADD KEY `SEC_UNQ` (`uid`,`music_id`) USING BTREE;
ALTER TABLE `slots` MODIFY `id` mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT;
我经常在uid
,music_id
和completed
之后查看。例如:
SELECT `music_id` FROM `slots` WHERE `uid` = :uid AND `completed` = :completed;
并按uid
和music_id
SELECT `music_id` FROM `slots` WHERE **`uid` = :uid AND `music_id` = :music_id**;
UPDATE `slots` SET xxx WHERE `uid` = :uid AND `music_id` = :music_id;
所以问题是:
我必须为以下所有列创建3个索引: uid , music_id 和已完成,或者只有它足够了 uid ? ..哪个更好,单列索引或多列索引?
PS:我在WHERE语句中总是有 uid
提前谢谢
答案 0 :(得分:1)
您可以轻松测试它。一个好的索引总是最好的,也适用于小型布尔值。它真的很容易理解:如果你有一个大表mysql必须读孔表(FULL TABLE SCAN)找几行来更新或删除。但MySQL几乎只能为每个查询使用一个索引。所以复合索引是有用的。 MySQL也可以将它们用于单个字段。假设你在字段(a,b,c)上有一个复合索引,如果只有a,a和b或a和b和c,MySQL可以在WHERE子句中使用它们,但不仅仅是在c或b上。
Hier是一个样本。在那里你可以看到MySQL必须阅读的man行以及使用的索引:
删除表并创建新的
MariaDB []> DROP TABLE IF EXISTS mytable;
Query OK, 0 rows affected (0.29 sec)
MariaDB []>
MariaDB []> CREATE TABLE `mytable` (
-> `id` INT(11) UNSIGNED NOT NULL,
-> `a` INT(11) DEFAULT NULL,
-> `b` INT(11) DEFAULT NULL,
-> `c` INT(11) DEFAULT NULL,
-> PRIMARY KEY (`id`)
-> ) ENGINE=INNODB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.24 sec)
MariaDB []>
插入3000000 ROWS(仅限MariaDB)
MariaDB []> INSERT INTO mytable (id,a,b,c)
-> SELECT seq, (seq MOD 2), (seq MOD 3) , (seq MOD 4) FROM seq_0_to_3000000;
Query OK, 3000001 rows affected (15.66 sec)
Records: 3000001 Duplicates: 0 Warnings: 0
MariaDB []>
在字段a上测试WHERE - MySQL读取2995634行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1;
+------+-------------+---------+------+---------------+------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+---------------+------+---------+------+---------+-------------+
| 1 | SIMPLE | mytable | ALL | NULL | NULL | NULL | NULL | 2995634 | Using where |
+------+-------------+---------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.12 sec)
在字段a上添加密钥
MariaDB []> ALTER TABLE mytable ADD KEY key_a (a);
Query OK, 0 rows affected (10.74 sec)
Records: 0 Duplicates: 0 Warnings: 0
再次测试最后一个查询(WHERE a) - MySQL只读取1496635行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1;
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------+
| 1 | SIMPLE | mytable | ref | key_a | key_a | 5 | const | 1496635 | |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------+
1 row in set (0.00 sec)
在fiels a和b上测试WHERE - 1496635行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1 AND b=2;
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
| 1 | SIMPLE | mytable | ref | key_a | key_a | 5 | const | 1496635 | Using where |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
1 row in set (0.00 sec)
在字段b上添加密钥
MariaDB []> ALTER TABLE mytable ADD KEY key_b (b);
Query OK, 0 rows affected (9.53 sec)
Records: 0 Duplicates: 0 Warnings: 0
与a和b相同的测试 - 相同的行 - 仅使用key_a
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1 AND b=2;
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
| 1 | SIMPLE | mytable | ref | key_a,key_b | key_a | 5 | const | 1496635 | Using where |
+------+-------------+---------+------+---------------+-------+---------+-------+---------+-------------+
1 row in set (0.00 sec)
在a和b上创建索引
MariaDB []> ALTER TABLE mytable ADD KEY key_ab (a,b);
Query OK, 0 rows affected (11.86 sec)
Records: 0 Duplicates: 0 Warnings: 0
使用a和b进行测试 - 使用key_ab并且只读取946702行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1 AND b=2;
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------+
| 1 | SIMPLE | mytable | ref | key_a,key_b,key_ab | key_ab | 10 | const,const | 946702 | |
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------+
1 row in set (0.01 sec)
使用字段a,b和c测试 - 使用kay_ab并读取946702行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1 AND b=2 AND c=3;
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------------+
| 1 | SIMPLE | mytable | ref | key_a,key_b,key_ab | key_ab | 10 | const,const | 946702 | Using where |
+------+-------------+---------+------+--------------------+--------+---------+-------------+--------+-------------+
1 row in set (0.00 sec)
在字段a,b,c上添加密钥
MariaDB []> ALTER TABLE mytable ADD KEY key_abc (a,b,c);
Query OK, 0 rows affected (18.64 sec)
Records: 0 Duplicates: 0 Warnings: 0
使用字段a,b,c - 使用key_abc进行测试 - 并读取511082行
MariaDB []> EXPLAIN SELECT * FROM mytable WHERE a=1 AND b=2 AND c=3;
+------+-------------+---------+------+----------------------------+---------+---------+-------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+---------+------+----------------------------+---------+---------+-------------------+--------+-------------+
| 1 | SIMPLE | mytable | ref | key_a,key_b,key_ab,key_abc | key_abc | 15 | const,const,const | 511082 | Using index |
+------+-------------+---------+------+----------------------------+---------+---------+-------------------+--------+-------------+
1 row in set (0.01 sec)
所以效果最好的是复合索引,但它也取决于您使用的查询。