2

作为 PHP 应用程序的一部分,我遇到了以下查询。查询在 mysql 5.0 中运行很快(不到 1 秒),但在 mysql 5.1 及更高版本中大约需要 7 分钟才能完成。

返回的结果只有 3 行,但是当我strace在 5.1 服务器上的 mysqld 进程上运行此查询时,我可以看到它连续从Event表中读取数据几分钟(一个只有 7000 行、200 字节的表每行)——大概是多次重读。

所以问题是,我在这里遇到了什么不同,我该如何修改东西(查询或更好的一些 MySQL 设置),以便它在 5.1 下运行的速度与在 5.0 下运行的速度一样快。


参考数据

责备的查询

SELECT S.Sections_ID, S.Sections_Name, S.Sections_CustomURL
FROM Sections S
WHERE S.Sections_Status = 'Active'
    AND S.Sections_Name!='Hidden'
    AND S.Sections_ParentID = 0
    AND S.Sections_MainSection = 1
    AND (
        SELECT COUNT(MainEvent.Event_ID) AS tot
        FROM Event MainEvent, Event_Section ES
        WHERE ES.EventSection_EventID=MainEvent.Event_ID
            AND ES.EventSection_SectionID=S.Sections_ID
            AND (
                (MainEvent.Event_DateTime > '2011-12-27 18:05:00')
                OR
                    (
                        (
                        SELECT ChildEvent.Event_DateTime
                        FROM Event ChildEvent
                        WHERE ChildEvent.Event_ParentEventID=MainEvent.Event_ID
                        ORDER BY ChildEvent.Event_DateTime DESC LIMIT 1
                        ) > '2011-12-27 18:05:00'
                    )
                )
            AND (MainEvent.Event_ParentEventID=0 or MainEvent.Event_ParentEventID IS NULL) 
            AND (MainEvent.Event_Status='Active' or MainEvent.Event_Status='Canceled') 
            AND MainEvent.Event_ID IN (
                SELECT
                Event_Website.EventWebsite_EventID
                FROM Event_Website 
                WHERE Event_Website.EventWebsite_CompanyID='3'
            )
        )>0
ORDER BY S.Sections_Order ASC, S.Sections_Name ASC

引用的表具有以下行数

部分:60
事件:7000 事件_部分
:7000事件
_网站:15000

下面是EXPLAIN来自 5.0(快)和 5.1(慢)服务器的上述查询。
剪裁空间;希望我没有剪掉任何有用的东西。

慢 (5.1)

+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+
| id | table         | type        | possible_keys              | key                    | key_len | ref                              | rows | Extra                       |
+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+
|  1 | S             | ref         | Sections_ParentID          | Sections_ParentID      | 5       | const                            |   10 | Using where; Using filesort |
|  2 | MainEvent     | ref_or_null | PRIMARY,Event_DateTime,... | Event_ParentID         | 5       | const                            | 4582 | Using where                 |
|  2 | ES            | ref         | EventSection_EventID       | EventSection_EventID   | 10      | MainEvent.Event_ID,S.Sections_ID |    1 | Using where; Using index    |
|  4 | Event_Website | ref         | EventWebsite_CompanyID     | EventWebsite_CompanyID | 4       | const                            | 4421 | Using where                 |
|  3 | ChildEvent    | index       | Event_ParentID             | Event_DateTime         | 8       | NULL                             |    1 | Using where                 |
+----+---------------+-------------+----------------------------+------------------------+---------+----------------------------------+------+-----------------------------+

快速 (5.0)

+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+
| id | table         | type   | possible_keys             | key                    | key_len | ref                     | rows | Extra                       |
+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+
|  1 | S             | ref    | Sections_ParentID         | Sections_ParentID      | 5       | const                   |   10 | Using where; Using filesort | 
|  2 | ES            | index  | EventSection_EventID      | EventSection_EventID   | 10      | NULL                    | 5610 | Using where; Using index    | 
|  2 | MainEvent     | eq_ref | PRIMARY,Event_DateTime,...| PRIMARY                | 4       | ES.EventSection_EventID |    1 | Using where                 | 
|  4 | Event_Website | ref    | EventWebsite_CompanyID    | EventWebsite_CompanyID | 4       | const                   | 5809 | Using where                 | 
|  3 | ChildEvent    | ref    | Event_ParentID            | Event_ParentID         | 5       | MainEvent.Event_ID      |    4 | Using where; Using filesort | 
+----+---------------+--------+---------------------------+------------------------+---------+-------------------------+------+-----------------------------+
4

3 回答 3

2

重写的两个建议:

  1. 更改IN (SELECT ...)JOIN查询。

  2. 更改 (SELECT COUNT(MainEvent.Event_ID) ...) > 0EXISTS (SELECT * ...)

于 2011-12-28T17:34:40.957 回答
1

Mysql 版本 5.0 和 5.1(以及所有较低版本)不是以这种方式处理(依赖)子查询时使用的最佳版本。

如果您停留在这些版本上,请尝试将您的查询重写为联接。也使用

“{columnname} IN (SELECT .... FROM {tablename} WHERE ....)”

往往是性能杀手。将其拆分为 2 个查询通常比使用该语法更快。

执行第一个查询,获取所有需要的 ID,然后将这些 id 放在上面的查询中

“{columnname} IN(12、345、356、653 等...)”

MariaDB 已经部分解决了这个问题,并且是一个彻底的 MySQL 替代品。如果没有敏感数据,能否给我发送数据库转储,我将在 MariaDB 上对上述查询进行基准测试

于 2011-12-28T09:34:28.393 回答
1

我已经重写了您的查询,现在它使用 JOINS。我无法测试此查询,因为您尚未附加 db 架构。请附上您的问题。

SELECT S.Sections_ID, S.Sections_Name, S.Sections_CustomURL
FROM Sections AS S
JOIN Event_Section AS ES ON ES.EventSection_SectionID = S.Sections_ID
JOIN Event AS MainEvent ON ES.EventSection_EventID = MainEvent.Event_ID
JOIN Event_Website ON Event_Website.EventWebsite_EventID = MainEvent.Event_ID
LEFT JOIN Event AS ChildEvent ON ChildEvent.Event_ParentEventID = MainEvent.Event_ID
WHERE S.Sections_Status = 'Active'
    AND S.Sections_Name != 'Hidden'
    AND S.Sections_ParentID = 0
    AND S.Sections_MainSection = 1
    AND (MainEvent.Event_ParentEventID = 0 OR MainEvent.Event_ParentEventID IS NULL)
    AND (MainEvent.Event_DateTime > '2011-12-27 18:05:00' OR ChildEvent.Event_DateTime > '2011-12-27 18:05:00')
    AND (MainEvent.Event_Status='Active' OR MainEvent.Event_Status='Canceled')
    AND Event_Website.EventWebsite_CompanyID = '3'
GROUP BY S.Sections_ID
ORDER BY S.Sections_Order ASC, S.Sections_Name ASC
于 2011-12-28T18:54:08.410 回答