MySQL 服务器在执行简单查询后挂起

MySQL server hangs after executing a simple query

我在 ARM 机器上有一个 MySQL 服务器 运行ning,我有一个查询 运行 in phpmyadmin 通过 Web 界面(或 php 在网站上)

select * from some_table where id IN (select id from other_table)

这个简单的查询将导致 MySQL 服务挂起,直到重新启动。 这是什么原因?

换句话说:

如果我手动输入 ID(无论是 1 还是 100)都不会失败:

select * from some_table where id IN (1,2,3,4,5,6,7,8,9....120)

另一方面 - 如果 ID 是从内部查询生成的,则服务将挂起:

select * from some_table where id IN (select id from other_table)

我可以完全访问服务器,并且可以根据需要重新配置它。我该如何解决这个问题?

数据库服务器

Server: Localhost via UNIX socket

Server type: MySQL

Server version: 5.5.35-1ubuntu1 - (Ubuntu)

Protocol version: 10

User: root@localhost

Server charset: UTF-8 Unicode (utf8)

网络服务器

nginx/1.4.6

Database client version: libmysql - 5.5.35

PHP extension: mysqli

phpMyAdmin

Version information: 4.0.10deb1

P.S。我所说的挂起是指 mysql 变得没有反应。命令 top 将显示 MySQL 服务正在耗尽所有核心。通过命令 sudo /etc/init.d/mysql restart.

重新启动

P.P.S。挂起的完整查询。 fiddle: http://sqlfiddle.com/#!9/84fe8/1

select
    goo.t1_score,
    goo.t2_score,
    gr.t1_score,
    gr.t2_score,
    gr.unique_key
from games_ongoing goo, game_results gr
where
goo.id in (
        select max(id)
        from games_ongoing
        group by unique_key
        having count(id) >= 3 and MIN(t1_score) = MIN(t2_score) and MIN(t1_score) = 0
        )
and gr.unique_key = goo.unique_key

所以,回顾一下...这是一个中间结果

SELECT o.id o_id
     , o.t1_score o_t1_score
     , o.t2_score o_t2_score
     , r.t1_score r_t1_score
     , r.t2_score r_t2_score
     , r.unique_key
  FROM games_ongoing o
  JOIN game_results r
    ON r.unique_key = o.unique_key;
+------+------------+------------+------------+------------+------------+
| o_id | o_t1_score | o_t2_score | r_t1_score | r_t2_score | unique_key |
+------+------------+------------+------------+------------+------------+
|    1 |          0 |          0 |          1 |          3 | 111        |
|    2 |          0 |          1 |          1 |          3 | 111        |
|    3 |          0 |          2 |          1 |          3 | 111        |
|    4 |          1 |          2 |          1 |          3 | 111        |
|    5 |          1 |          2 |          1 |          3 | 111        |
|    6 |          0 |          0 |          5 |          4 | 222        |
|    7 |          1 |          1 |          5 |          4 | 222        |
|    8 |          2 |          1 |          5 |          4 | 222        |
+------+------------+------------+------------+------------+------------+

为了获得具有最高(持续)id 的唯一键,我们可以使用不相关的子查询,如下所示:

 SELECT x.*
      , r.*
   FROM games_ongoing x
   JOIN 
      ( SELECT unique_key, MAX(id) max_id FROM games_ongoing GROUP BY unique_key ) y
     ON y.unique_key = x.unique_key
    AND y.max_id = x.id
   JOIN game_results r
     ON r.unique_key = x.unique_key;

+----+---------+---------+------------+----------+----------+----+----------+----------+------------+
| id | t1_name | t2_name | unique_key | t1_score | t2_score | id | t1_score | t2_score | unique_key |
+----+---------+---------+------------+----------+----------+----+----------+----------+------------+
|  5 | team1   | team2   | 111        |        1 |        2 |  1 |        1 |        3 | 111        |
|  8 | team3   | team4   | 222        |        2 |        1 |  2 |        5 |        4 | 222        |
+----+---------+---------+------------+----------+----------+----+----------+----------+------------+

这应该比上面的查询执行得更好,但是为了进一步帮助优化它,我们需要查看 EXPLAIN。

回答你原来的问题。在 MySQL 中,此查询:

select * from some_table where id IN (select id from other_table)

将执行以下查询:

SELECT  id
FROM    other_table
WHERE   other_table.id = some_table.id

对于 some_table 中的每条记录,而这条:

select * from some_table where id IN (1,2,3,4,5,6,7,8,9....120)

将从 some_table 中的列表中寻找每个值。如果 some_table 上有很多记录,但 other_table 上的记录很少,你应该像这样重写查询:

SELECT  st.*
FROM    (
        SELECT  DISTINCT
                id
        FROM    other_table
        ) ot
JOIN    some_table st
ON      st.id = ot.id

这将在 some_table.id 的索引中搜索每个不同的 other_table.id

现在,假设没有负分,你应该运行这个查询:

SELECT  *
FROM    game_results gr
JOIN    games_ongoing goo
ON      goo.id =
        (
        SELECT  id
        FROM    games_ongoing goi
        WHERE   goi.unique_key = gr.unique_key
                AND EXISTS
                (
                SELECT  NULL
                FROM    games_ongoing goz
                WHERE   goz.unique_key = goi.unique_key
                        AND (goz.t1_score, goz.t2_score) = (0, 0)
                )
                AND EXISTS
                (
                SELECT  NULL
                FROM    games_ongoing goc
                WHERE   goc.unique_key = goi.unique_key
                LIMIT   2, 1
                )
        ORDER BY
                goi.unique_key DESC, goi.id DESC
        LIMIT   1
        )

为查询快速运行创建以下索引:

CREATE INDEX ix_game_results_unique_key ON game_results (unique_key);
CREATE INDEX ix_games_ongoing_unique_key ON games_ongoing (unique_key);
CREATE INDEX ix_games_ongoing_unique_key_t2_score_t2_score ON games_ongoing (unique_key, t1_score, t2_score);

参见fiddle:http://sqlfiddle.com/#!9/72444/1