使用索引优化MySQL查询(什么索引?)

时间:2022-09-17 23:05:19

I am struggling to optimize the following query which takes an average of 2000 ms.

我正在努力优化下面的查询,平均需要2000 ms。

select  count(pk)
    from  mytable
    where  (pk<>5
      and  url='test.png'
      and  (data=124578 or  (data is null and  pk=1234578)))
      and  type in (123,456,789,015,789) 

Here are some info :

以下是一些信息:

select count(*) from mytable

1 526 588 lines

1 526 588行

show indexes in mytable

Table   non_unique  key_name            seq_in_index    column_name collation   cardinality
mytable 0           PRIMARY             1               PK          A           1405079     
mytable 1           data                1               data        A           1405079     
mytable 1           Media_Code_30       1               code        A           1405079     
mytable 1           codeVersionIDX_30   1               code        A           1405079     

Explain :

解释:

id  select_type table   type        possible_keys   key     key_len ref     rows    extra
1   SIMPLE      mytable ref_or_null PRIMARY,data    data    9       const   635908  Using where

I really have no idea whether this is optimized enough, or it can be better by creating new indexes (or composite indexes).

我真的不知道这个优化是否足够,或者创建新的索引(或复合索引)会更好。

The query, however, cannot be changed as it is coming from another system on which I do not have my hands on!

但是,查询不能更改,因为它来自另一个系统,而我对此无能为力!

4 个解决方案

#1


2  

Hmmm, this query seems difficult to set up an index for:

嗯,这个查询似乎很难建立一个索引:

select count(pk)
from mytable
where (pk <> 5 and url = 'test.png' and
       (data = 124578 or (data is null and pk = 1234578))
      ) and
      type in (123, 456, 789, 015, 789);

My suggestion is to start with type and include the other columns in the index: mytable(type, url, data, pk). This is a covering index and that might improve performance a bit.

我的建议是从类型开始,包括索引中的其他列:mytable(类型、url、数据、pk)。这是一个覆盖指标,可能会提高性能。

#2


2  

This is not the Answer. Only some sample for using index

这不是答案。只有一些使用索引的样本。

SAMPLE

样本

small Table

小桌子

MariaDB [bb]> SHOW CREATE TABLE useindex\G
*************************** 1. row ***************************
       Table: useindex
Create Table: CREATE TABLE `useindex` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `num1` int(11) DEFAULT NULL,
  `num2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2031586 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

number of rows and sample data

行数和示例数据

MariaDB [bb]> SELECT count(*) FROM USEindex;
+----------+
| count(*) |
+----------+
|  2000000 |
+----------+
1 row in set (0.43 sec)

MariaDB [bb]> SELECT * FROM useindex LIMIT 10;
+----+------+------+
| id | num1 | num2 |
+----+------+------+
|  1 |  405 |  906 |
|  2 |  656 |  656 |
|  3 |  906 |  407 |
|  4 |  156 |  157 |
|  5 |  406 |  908 |
|  6 |  656 |  659 |
|  7 |  907 |  409 |
|  8 |  157 |  160 |
|  9 |  407 |  910 |
| 10 |  657 |  661 |
+----+------+------+
10 rows in set (0.00 sec)

EXPLAIN 3 queries (no index)

解释3个查询(无索引)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

add 2 indexe

加上2 indexe

MariaDB [bb]> ALTER TABLE useindex
    -> ADD KEY n1 (num1),
    -> ADD KEY n2 (num2);
Query OK, 0 rows affected (12.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

EXPLAIN with index

解释与指数

see if the WHERE with 2 fields, MySQL use only one INDEX

看看有两个字段的地方,MySQL是否只使用一个索引

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n1            | n1   | 5       | const | 2003 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n2            | n2   | 5       | const | 1993 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n2         | n2   | 5       | const | 1993 | Using where |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)

add COMPOSITE Index over both fields

在两个字段上添加复合索引

MariaDB [bb]> ALTER TABLE useindex
    -> ADD KEY n12 (num1,num2);
Query OK, 0 rows affected (7.83 sec)
Records: 0  Duplicates: 0  Warnings: 0

EXPLAIN Queries again

解释再次查询

Now they use the COMOSITE Index

现在他们使用了魔岛网站索引

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n12        | n12  | 5       | const | 2003 | Using index |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n2            | n2   | 5       | const | 1993 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref         | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n2,n12     | n12  | 10      | const,const |    1 | Using index |
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
1 row in set (0.00 sec)

Tell the OPTIMIZER to MERGE INDEX

告诉优化器合并索引

MariaDB [bb]> SET optimizer_switch='index_merge=on';
Query OK, 0 rows affected (0.00 sec)

drop INDEX n12

下降指数n12

MariaDB [bb]> alter table useindex drop key n12;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

RUN one QUERY with MERGE

使用MERGE运行一个查询

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
| id   | select_type | table    | type        | possible_keys | key   | key_len | ref  | rows | Extra                                            |
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
|    1 | SIMPLE      | useindex | index_merge | n1,n2         | n2,n1 | 5,5     | NULL |    1 | Using intersect(n2,n1); Using where; Using index |
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [bb]>

#3


0  

MySQL can only use one INDEX in a query.

MySQL只能在查询中使用一个索引。

so it is necessary to have composite index. the best way for the order of the fields in the index is the field which reduce the resultset mostly and so on.

因此有必要建立复合指数。索引中字段的顺序最好的方法是减少结果集的字段,依此类推。

lets say you have a table with names and birthday and you have many duplicates of names and only a few of birthday. so then create the index like (birthday,name) the mysql search first the records with the searched day and then only in this little result the name

假设你有一张桌子,上面有名字和生日,你有很多重复的名字,只有几个生日。然后创建索引,比如(生日,名字)mysql搜索,先搜索记录和搜索日期,然后在这个小的结果中输入名字

#4


0  

The best index for that query is

该查询的最佳索引是

INDEX(url, type) -- in that order

Indexes should start with any columns that are "= constant" (url in this case), then move on to one more column that is more complex (type IN ...). See my cookbook.

索引应该从“= constant”(本例中为url)的任何列开始,然后再移动到更复杂的列(输入…)。看到我的食谱。

#1


2  

Hmmm, this query seems difficult to set up an index for:

嗯,这个查询似乎很难建立一个索引:

select count(pk)
from mytable
where (pk <> 5 and url = 'test.png' and
       (data = 124578 or (data is null and pk = 1234578))
      ) and
      type in (123, 456, 789, 015, 789);

My suggestion is to start with type and include the other columns in the index: mytable(type, url, data, pk). This is a covering index and that might improve performance a bit.

我的建议是从类型开始,包括索引中的其他列:mytable(类型、url、数据、pk)。这是一个覆盖指标,可能会提高性能。

#2


2  

This is not the Answer. Only some sample for using index

这不是答案。只有一些使用索引的样本。

SAMPLE

样本

small Table

小桌子

MariaDB [bb]> SHOW CREATE TABLE useindex\G
*************************** 1. row ***************************
       Table: useindex
Create Table: CREATE TABLE `useindex` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `num1` int(11) DEFAULT NULL,
  `num2` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2031586 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

number of rows and sample data

行数和示例数据

MariaDB [bb]> SELECT count(*) FROM USEindex;
+----------+
| count(*) |
+----------+
|  2000000 |
+----------+
1 row in set (0.43 sec)

MariaDB [bb]> SELECT * FROM useindex LIMIT 10;
+----+------+------+
| id | num1 | num2 |
+----+------+------+
|  1 |  405 |  906 |
|  2 |  656 |  656 |
|  3 |  906 |  407 |
|  4 |  156 |  157 |
|  5 |  406 |  908 |
|  6 |  656 |  659 |
|  7 |  907 |  409 |
|  8 |  157 |  160 |
|  9 |  407 |  910 |
| 10 |  657 |  661 |
+----+------+------+
10 rows in set (0.00 sec)

EXPLAIN 3 queries (no index)

解释3个查询(无索引)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref  | rows    | Extra       |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
|    1 | SIMPLE      | useindex | ALL  | NULL          | NULL | NULL    | NULL | 1996444 | Using where |
+------+-------------+----------+------+---------------+------+---------+------+---------+-------------+
1 row in set (0.00 sec)

add 2 indexe

加上2 indexe

MariaDB [bb]> ALTER TABLE useindex
    -> ADD KEY n1 (num1),
    -> ADD KEY n2 (num2);
Query OK, 0 rows affected (12.08 sec)
Records: 0  Duplicates: 0  Warnings: 0

EXPLAIN with index

解释与指数

see if the WHERE with 2 fields, MySQL use only one INDEX

看看有两个字段的地方,MySQL是否只使用一个索引

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n1            | n1   | 5       | const | 2003 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n2            | n2   | 5       | const | 1993 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n2         | n2   | 5       | const | 1993 | Using where |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)

add COMPOSITE Index over both fields

在两个字段上添加复合索引

MariaDB [bb]> ALTER TABLE useindex
    -> ADD KEY n12 (num1,num2);
Query OK, 0 rows affected (7.83 sec)
Records: 0  Duplicates: 0  Warnings: 0

EXPLAIN Queries again

解释再次查询

Now they use the COMOSITE Index

现在他们使用了魔岛网站索引

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n12        | n12  | 5       | const | 2003 | Using index |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref   | rows | Extra |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
|    1 | SIMPLE      | useindex | ref  | n2            | n2   | 5       | const | 1993 |       |
+------+-------------+----------+------+---------------+------+---------+-------+------+-------+
1 row in set (0.00 sec)

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
| id   | select_type | table    | type | possible_keys | key  | key_len | ref         | rows | Extra       |
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
|    1 | SIMPLE      | useindex | ref  | n1,n2,n12     | n12  | 10      | const,const |    1 | Using index |
+------+-------------+----------+------+---------------+------+---------+-------------+------+-------------+
1 row in set (0.00 sec)

Tell the OPTIMIZER to MERGE INDEX

告诉优化器合并索引

MariaDB [bb]> SET optimizer_switch='index_merge=on';
Query OK, 0 rows affected (0.00 sec)

drop INDEX n12

下降指数n12

MariaDB [bb]> alter table useindex drop key n12;
Query OK, 0 rows affected (0.07 sec)
Records: 0  Duplicates: 0  Warnings: 0

RUN one QUERY with MERGE

使用MERGE运行一个查询

MariaDB [bb]> EXPLAIN SELECT * FROM useindex WHERE num1 = 500 AND num2 = 600;
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
| id   | select_type | table    | type        | possible_keys | key   | key_len | ref  | rows | Extra                                            |
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
|    1 | SIMPLE      | useindex | index_merge | n1,n2         | n2,n1 | 5,5     | NULL |    1 | Using intersect(n2,n1); Using where; Using index |
+------+-------------+----------+-------------+---------------+-------+---------+------+------+--------------------------------------------------+
1 row in set (0.00 sec)

MariaDB [bb]>

#3


0  

MySQL can only use one INDEX in a query.

MySQL只能在查询中使用一个索引。

so it is necessary to have composite index. the best way for the order of the fields in the index is the field which reduce the resultset mostly and so on.

因此有必要建立复合指数。索引中字段的顺序最好的方法是减少结果集的字段,依此类推。

lets say you have a table with names and birthday and you have many duplicates of names and only a few of birthday. so then create the index like (birthday,name) the mysql search first the records with the searched day and then only in this little result the name

假设你有一张桌子,上面有名字和生日,你有很多重复的名字,只有几个生日。然后创建索引,比如(生日,名字)mysql搜索,先搜索记录和搜索日期,然后在这个小的结果中输入名字

#4


0  

The best index for that query is

该查询的最佳索引是

INDEX(url, type) -- in that order

Indexes should start with any columns that are "= constant" (url in this case), then move on to one more column that is more complex (type IN ...). See my cookbook.

索引应该从“= constant”(本例中为url)的任何列开始,然后再移动到更复杂的列(输入…)。看到我的食谱。