0

我有一个完美的连接查询,有时我从表 EventKeyReference 中获取 eventKey、标签和 dataUnit,从 EventData 中获取 valueParam,从表 EventHeader 中获取时间戳。在我的 where 子句中,我有 Unit u.id = 3。这很好用。但是,当我尝试搜索 Unit u.id = 1 时,查询有时可能需要 20 秒。

搜索 id = 3

SELECT ek.eventKey, ek.label, ek.dataUnit, ed.valueParam, eh.timestamp
FROM EventKeyReference AS ek 
INNER JOIN UnitReference_EventKeyReference AS urek ON urek.eventKeyReferences_id = ek.id 
INNER JOIN UnitReference AS ur ON ur.id = urek.UnitReference_id
INNER JOIN Unit AS un ON un.id = ur.unit_id INNER JOIN User AS u ON u.id = ur.user_id
INNER JOIN EventData AS ed ON ek.eventKey = ed.keyParam
INNER JOIN EventHeader AS eh ON eh.id = ed.eventHeader_id
WHERE ek.eventKey = 'C004' AND u.id = 3 AND un.serialNumber=221148096
ORDER BY eh.timestamp LIMIT 1;

给出了这个:

+----------+----------+----------+------------+---------------------+
| eventKey | label    | dataUnit | valueParam | timestamp           |
+----------+----------+----------+------------+---------------------+
| C004     | Utgang 2 | on/off   | 0          | 2000-01-01 00:01:04 |
+----------+----------+----------+------------+---------------------+
1 row in set (0.00 sec)

搜索 id = 1 给出:

+----------+-------------+----------+------------+---------------------+
| eventKey | label       | dataUnit | valueParam | timestamp           |
+----------+-------------+----------+------------+---------------------+
| C004     | DigitalOut1 | ON/OFF   | 0          | 2000-01-01 00:01:04 |
+----------+-------------+----------+------------+---------------------+
1 row in set (16.04 sec)

如您所见,执行查询需要 16 秒。

在检查 EXPLAIN SELECT 时,我得到了这个。

    mysql> EXPLAIN SELECT ek.eventKey, ek.label, ek.dataUnit, ed.valueParam,    eh.timestamp   FROM EventKeyReference AS ek INNER JOIN UnitReference_EventKeyReference AS urek ON urek.eventKeyReferences_id = ek.id INNER JOIN UnitReference AS ur ON ur.id = urek.UnitReference_id  INNER JOIN Unit AS un ON un.id = ur.unit_id INNER JOIN User AS u ON u.id = ur.user_id INNER JOIN EventData AS ed ON ek.eventKey = ed.keyParam INNER JOIN EventHeader AS eh ON eh.id = ed.eventHeader_id   WHERE ek.eventKey = 'C004' AND u.id = 1 AND un.serialNumber=221148096 ORDER BY eh.timestamp DESC LIMIT 1;
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+--------+----------------------------------------------+
| id | select_type | table | type   | possible_keys                                 | key                | key_len | ref                                | rows   | Extra                                        |
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+--------+----------------------------------------------+
|  1 | SIMPLE      | u     | const  | PRIMARY                                       | PRIMARY            | 8       | const                              |      1 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | eh    | index  | PRIMARY                                       | eh_timestamp       | 9       | NULL                               | 169161 | Using index                                  |
|  1 | SIMPLE      | ed    | ref    | FK794A194417A622D6                            | FK794A194417A622D6 | 9       | fltcoor.eh.id                      |      5 | Using where                                  |
|  1 | SIMPLE      | ur    | range  | PRIMARY,FK83382A0747140EFE,FK83382A073EC5085E | FK83382A0747140EFE | 9       | NULL                               |      3 | Using where; Using join buffer               |
|  1 | SIMPLE      | urek  | ref    | PRIMARY,FKAC98AB0E2DFCBD8F,FKAC98AB0E564AEB96 | FKAC98AB0E564AEB96 | 8       | fltcoor.ur.id                      |     11 | Using index                                  |
|  1 | SIMPLE      | un    | eq_ref | PRIMARY,serialNumber                          | PRIMARY            | 8       | fltcoor.ur.unit_id                 |      1 | Using where                                  |
|  1 | SIMPLE      | ek    | eq_ref | PRIMARY                                       | PRIMARY            | 8       | fltcoor.urek.eventKeyReferences_id |      1 | Using where                                  |
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+--------+----------------------------------------------+
7 rows in set (0.00 sec)

mysql> EXPLAIN SELECT ek.eventKey, ek.label, ek.dataUnit, ed.valueParam, eh.timestamp   FROM EventKeyReference AS ek INNER JOIN UnitReference_EventKeyReference AS urek ON urek.eventKeyReferences_id = ek.id INNER JOIN UnitReference AS ur ON ur.id = urek.UnitReference_id  INNER JOIN Unit AS un ON un.id = ur.unit_id INNER JOIN User AS u ON u.id = ur.user_id INNER JOIN EventData AS ed ON ek.eventKey = ed.keyParam INNER JOIN EventHeader AS eh ON eh.id = ed.eventHeader_id   WHERE ek.eventKey = 'C004' AND u.id = 3 AND un.serialNumber=221148096 ORDER BY eh.timestamp DESC LIMIT 1;
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+------+-------------+
| id | select_type | table | type   | possible_keys                                 | key                | key_len | ref                                | rows | Extra       |
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+------+-------------+
|  1 | SIMPLE      | u     | const  | PRIMARY                                       | PRIMARY            | 8       | const                              |    1 | Using index |
|  1 | SIMPLE      | eh    | index  | PRIMARY                                       | eh_timestamp       | 9       | NULL                               |    1 | Using index |
|  1 | SIMPLE      | ur    | ref    | PRIMARY,FK83382A0747140EFE,FK83382A073EC5085E | FK83382A0747140EFE | 9       | const                              |    2 | Using where |
|  1 | SIMPLE      | un    | eq_ref | PRIMARY,serialNumber                          | PRIMARY            | 8       | fltcoor.ur.unit_id                 |    1 | Using where |
|  1 | SIMPLE      | ed    | ref    | FK794A194417A622D6                            | FK794A194417A622D6 | 9       | fltcoor.eh.id                      |    5 | Using where |
|  1 | SIMPLE      | urek  | ref    | PRIMARY,FKAC98AB0E2DFCBD8F,FKAC98AB0E564AEB96 | FKAC98AB0E564AEB96 | 8       | fltcoor.ur.id                      |   11 | Using index |
|  1 | SIMPLE      | ek    | eq_ref | PRIMARY                                       | PRIMARY            | 8       | fltcoor.urek.eventKeyReferences_id |    1 | Using where |
+----+-------------+-------+--------+-----------------------------------------------+--------------------+---------+------------------------------------+------+-------------+
7 rows in set (0.00 sec)

出于某种原因,在 id = 1 的查询中,MYSQL 会经过大约 16.000 行。

这一直困扰着我一整天,因为我找不到为什么会发生这种情况。如果有更多信息,我很乐意提供,因为我自己离 Mysql 专家还很远。

4

2 回答 2

2

正如 Jakob 所说,如果您有 160000 个用户 1 条目,那可能是您的瓶颈。我已经重写,希望能有所帮助。我更改了顺序,希望将最小的粒度块放在查询的主要位置并从那里链接起来。我怀疑给定序列号的记录非常少,因此将其放入 WHERE 子句并添加辅助条件(通过实施的 ON / AND 子句)应该会有所帮助。

SELECT 
      ek.eventKey, 
      ek.label, 
      ek.dataUnit, 
      ed.valueParam, 
      eh.timestamp
   FROM 
      Unit AS un 
         INNER JOIN UnitReference AS ur 
            ON un.id = ur.unit_id
            AND ur.user_id = 3      <==  ADDED USER ID CRITERIA HERE
            INNER JOIN User AS u 
               ON ur.user_id = u.id
            INNER JOIN UnitReference_EventKeyReference AS urek 
               ON ur.id = urek.UnitReference_id
               INNER JOIN EventKeyReference AS ek 
                  ON urek.eventKeyReferences_id = ek.id
                  AND ek.eventKey = 'C004'   <== ADDED EVENT KEY CRITERIA HERE
               INNER JOIN EventData AS ed 
                  ON ek.eventKey = ed.keyParam
                  INNER JOIN EventHeader AS eh 
                     ON ed.eventHeader_id = eh.id
   WHERE 
      un.serialNumber=221148096
   ORDER BY 
      eh.timestamp LIMIT 1;

如果上述方法不起作用,我会尝试的唯一其他项目,并且因为它是 MySQL,我会再添加一个关键字......

SELECT STRAIGHT_JOIN [查询的其余部分]

它告诉 MySQL 按照您声明的顺序进行查询,而不是尝试以不同的顺序为您考虑。

于 2013-10-28T15:32:58.340 回答
1

您的查询实际上正在执行您要求它执行的操作。我的怀疑是你实际上有 160000+ 行 u.id = 1 而你只有一行 u.id = 3。看看你的解释你可以看到你的查询实际上在两个查询上都使用了索引。但是在一种情况下,您会循环超过 160000+ 行,因为这是 u.id = 1 的行数。我敢打赌,如果您删除 limit 1 子句,您将获得许多慢查询的结果。

于 2013-10-28T15:10:27.337 回答