【问题标题】:MySQL server hangs after executing a simple queryMySQL 服务器在执行简单查询后挂起
【发布时间】:2015-03-18 13:48:51
【问题描述】:

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

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)

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

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

附:我所说的挂起是指mysql 变得无响应。命令top 将显示 MySQL 服务正在耗尽所有内核。通过命令sudo /etc/init.d/mysql restart完成重启。

附言挂起的完整查询。小提琴: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

【问题讨论】:

  • 你正在使用子查询,这就是为什么
  • 你为什么要这样做? JOIN 有什么问题?
  • 使用子查询有什么问题?我整天都在 oracle 中这样做
  • @Strawberry 在完整的子查询中,我还使用了 GROUP BY 语句。甚至可以将其转换为 JOIN 吗?
  • 您的查询不太有意义(除非两个表之间可能存在 1-1 相关性,但 MAX 将没有意义)。考虑遵循这个简单的两步课程行动: 1. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。

标签: php mysql phpmyadmin server


【解决方案1】:

回答您最初的问题。在 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);

见小提琴:http://sqlfiddle.com/#!9/72444/1

【讨论】:

  • 感谢您的解释!我没有尝试添加索引,但没有它们 - 服务器照常挂起。我稍后会尝试添加索引,可能会解决问题。
【解决方案2】:

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

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。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-07-02
  • 2020-12-01
  • 1970-01-01
  • 2018-08-01
  • 2011-09-01
相关资源
最近更新 更多