添加 OR 语句时查询速度慢 MySQL

Slow MySQL query when adding an OR statement

这是我要优化的查询:

SELECT SUM(`backend_ubqstat`.`complementary_revenue`) AS `complementary_revenue__sum`, SUM(`backend_ubqstat`.`revenue`) AS `revenue__sum` FROM `backend_ubqstat` 
INNER JOIN `backend_ubq` ON ( `backend_ubqstat`.`ubq_id` = `backend_ubq`.`id` ) 
WHERE 
(`backend_ubqstat`.`store_number` = 389 AND (`backend_ubqstat`.`week_of_year` = 2 OR `backend_ubqstat`.`week_of_year` = 3) 
AND (`backend_ubq`.`department` = 'QUINCAILLERIE' OR `backend_ubq`.`department` = 'OUTILLAGE') 
AND (`backend_ubq`.`sub_department` = 'Outillage à moteur' OR `backend_ubq`.`sub_department` = 'Outillage à main' OR `backend_ubq`.`sub_department` = 'Outil d\'assemblage'));

执行此查询需要 73 秒。同样的查询只用了一周 (backend_ubqstat.week_of_year = 2 没有 OR):

SELECT SUM(`backend_ubqstat`.`complementary_revenue`) AS `complementary_revenue__sum`, SUM(`backend_ubqstat`.`revenue`) AS `revenue__sum` FROM `backend_ubqstat` 
INNER JOIN `backend_ubq` ON ( `backend_ubqstat`.`ubq_id` = `backend_ubq`.`id` ) 
WHERE 
(`backend_ubqstat`.`store_number` = 389 AND (`backend_ubqstat`.`week_of_year` = 2) 
AND (`backend_ubq`.`department` = 'QUINCAILLERIE' OR `backend_ubq`.`department` = 'OUTILLAGE') 
AND (`backend_ubq`.`sub_department` = 'Outillage à moteur' OR `backend_ubq`.`sub_department` = 'Outillage à main' OR `backend_ubq`.`sub_department` = 'Outil d\'assemblage'));

执行需要 0.1 秒。我试图了解第一个查询的主要问题是什么。

此查询计算特定商店一周内某些产品的收入总和。

I 运行 EXPLAIN 对两个查询的结果如下:

多周(第一次查询):

+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+------------------------------------+
| id | select_type | table           | type   | possible_keys                                                                                                                                                                            | key                                               | key_len | ref                                | rows | Extra                              |
+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+------------------------------------+
|  1 | SIMPLE      | backend_ubqstat | range  | backend_ubq_store_number_4ba08aefde7a0fdc_uniq,backend_ubq_ubq_id_2883f2962b976ce1_uniq,backend_ubq_week_of_year_534972be244e06dd_uniq,backend_ubqstat_week_of_year_1f3b84a6cf9999f7_idx | backend_ubqstat_week_of_year_1f3b84a6cf9999f7_idx | 4       | NULL                               | 2975 | Using index condition; Using where |
|  1 | SIMPLE      | backend_ubq     | eq_ref | PRIMARY,backend_ubq_department_2cef48a6c5825cef_uniq,backend_ubq_sub_department_65793aef847267e8_uniq,backend_ubq_department_2ebadbdc749719ff_idx                                        | PRIMARY                                           | 4       | xxxxxxxxxxx.backend_ubqstat.ubq_id |    1 | Using where                        |
+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+------------------------------------+

仅一周(第二次查询):

+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+-------------+
| id | select_type | table           | type   | possible_keys                                                                                                                                                                            | key                                               | key_len | ref                                | rows | Extra       |
+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+-------------+
|  1 | SIMPLE      | backend_ubqstat | ref    | backend_ubq_store_number_4ba08aefde7a0fdc_uniq,backend_ubq_ubq_id_2883f2962b976ce1_uniq,backend_ubq_week_of_year_534972be244e06dd_uniq,backend_ubqstat_week_of_year_1f3b84a6cf9999f7_idx | backend_ubqstat_week_of_year_1f3b84a6cf9999f7_idx | 4       | const,const                        | 1475 | Using where |
|  1 | SIMPLE      | backend_ubq     | eq_ref | PRIMARY,backend_ubq_department_2cef48a6c5825cef_uniq,backend_ubq_sub_department_65793aef847267e8_uniq,backend_ubq_department_2ebadbdc749719ff_idx                                        | PRIMARY                                           | 4       | xxxxxxxxx.backend_ubqstat.ubq_id |    1 | Using where |
+----+-------------+-----------------+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+---------------------------------------------------+---------+------------------------------------+------+-------------+

这些是两个 table 的架构: Table 个产品: mysql> 描述 backend_ubq;

+----------------+----------------------+------+-----+---------+----------------+
| Field          | Type                 | Null | Key | Default | Extra          |
+----------------+----------------------+------+-----+---------+----------------+
| id             | int(11)              | NO   | PRI | NULL    | auto_increment |
| ub             | varchar(30)          | NO   |     | NULL    |                |
| department     | varchar(30)          | NO   | MUL | NULL    |                |
| sub_department | varchar(50)          | NO   | MUL | NULL    |                |
| family         | varchar(50)          | NO   | MUL | NULL    |                |
| sub_family_id  | smallint(5) unsigned | NO   |     | NULL    |                |
| sub_family     | varchar(50)          | NO   | MUL | NULL    |                |
| brand          | varchar(50)          | NO   | MUL | NULL    |                |
| quartile       | smallint(5) unsigned | NO   | MUL | NULL    |                |
+----------------+----------------------+------+-----+---------+----------------+

这个table有3604行。

Table 每个产品的收入按周数和商店数划分: mysql> 描述 backend_ubq统计数据;

+-----------------------+----------------------+------+-----+---------+----------------+
| Field                 | Type                 | Null | Key | Default | Extra          |
+-----------------------+----------------------+------+-----+---------+----------------+
| id                    | int(11)              | NO   | PRI | NULL    | auto_increment |
| ubq_id                | int(11)              | YES  | MUL | NULL    |                |
| week_of_year          | smallint(5) unsigned | NO   | MUL | NULL    |                |
| month_of_year         | smallint(5) unsigned | NO   |     | NULL    |                |
| year                  | smallint(5) unsigned | NO   | MUL | NULL    |                |
| store_number          | smallint(5) unsigned | NO   | MUL | NULL    |                |
| nb_tickets            | smallint(5) unsigned | NO   |     | NULL    |                |
| nb_items              | smallint(5) unsigned | NO   |     | NULL    |                |
| revenue               | decimal(9,2)         | NO   |     | NULL    |                |
| complementary_revenue | decimal(9,2)         | NO   |     | NULL    |                |
+-----------------------+----------------------+------+-----+---------+----------------+

这个 table 有 20 832 730 行。

我正在使用 MySQL 5.6。

我做了一些研究,但找不到解决我的问题的方法。我应该怎么做才能使第一个查询 运行 更快?

当该列甚至被索引并且您使用 OR 时,优化器将无法使用索引。对于您的情况,如果列 week_of_year 未编入索引,那么您可以索引该列。现在要解决此问题,您可以使用 UNION 并将 OR 条件移动为 2 个不同的查询,如下所示。尝试使用 Explain 看看你得到了什么。

SELECT 
SUM(`backend_ubqstat`.`complementary_revenue`) AS `complementary_revenue__sum`, 
SUM(`backend_ubqstat`.`revenue`) AS `revenue__sum` 
FROM `backend_ubqstat` 
INNER JOIN `backend_ubq` ON ( `backend_ubqstat`.`ubq_id` = `backend_ubq`.`id` ) 
WHERE 
(
  `backend_ubqstat`.`store_number` = 389 AND `backend_ubqstat`.`week_of_year` = 2 
  AND (`backend_ubq`.`department` = 'QUINCAILLERIE' OR `backend_ubq`.`department` = 'OUTILLAGE') 
  AND (`backend_ubq`.`sub_department` = 'Outillage à moteur' OR `backend_ubq`.`sub_department` = 'Outillage à main' OR `backend_ubq`.`sub_department` = 'Outil d\'assemblage')
)
union
SELECT 
SUM(`backend_ubqstat`.`complementary_revenue`) AS `complementary_revenue__sum`, 
SUM(`backend_ubqstat`.`revenue`) AS `revenue__sum` 
FROM `backend_ubqstat` 
INNER JOIN `backend_ubq` ON ( `backend_ubqstat`.`ubq_id` = `backend_ubq`.`id` ) 
WHERE 
(
  `backend_ubqstat`.`store_number` = 389 AND `backend_ubqstat`.`week_of_year` = 3 
  AND (`backend_ubq`.`department` = 'QUINCAILLERIE' OR `backend_ubq`.`department` = 'OUTILLAGE') 
  AND (`backend_ubq`.`sub_department` = 'Outillage à moteur' OR `backend_ubq`.`sub_department` = 'Outillage à main' OR `backend_ubq`.`sub_department` = 'Outil d\'assemblage')
)