多列INDEX和单列INDEX SQL / PHP

时间:2016-05-03 18:04:30

标签: mysql

这是我的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;

我经常在uidmusic_idcompleted之后查看。例如:

SELECT `music_id` FROM `slots` WHERE `uid` = :uid AND `completed` = :completed;

并按uidmusic_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

提前谢谢

1 个答案:

答案 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)

所以效果最好的是复合索引,但它也取决于您使用的查询。