【问题标题】:simple mysql query taking 16+ seconds简单的 mysql 查询需要 16 秒以上
【发布时间】:2014-01-02 09:35:48
【问题描述】:

简单的 sql 查询需要 16 秒以上。这是表格。

CREATE TABLE IF NOT EXISTS `udr` (
  `userid` int(11) NOT NULL DEFAULT '0',
  `time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `upbytes` int(11) NOT NULL DEFAULT '0',
  `downbytes` int(11) NOT NULL DEFAULT '0',
  `traffictype` int(11) NOT NULL DEFAULT '1',
  KEY `userid` (`userid`),
  KEY `time` (`time`),
  KEY `traffictype` (`traffictype`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

有 1600 万条记录。 (原来有1.41亿,我剪了看看是不是问题)

有问题的查询是(喜欢)

select time,upbytes,downbytes
 from udr
  where userid = 315533 and 
        time between '2014-01-01 14:35:28' and '2014-01-02 14:35:28'

我认为问题出在时间部分,所以我删除了时间条件并尝试遵循

select time,upbytes,downbytes from udr where userid = 315533
...
10282 rows in set (19.42 sec)

查询仍然需要 16 秒以上。

这是我的关键配置参数

key_buffer    = 32M
max_allowed_packet  = 16M
thread_stack    = 192K
thread_cache_size       = 8
query_cache_limit = 1M
query_cache_size        = 16M

没有关于这个的想法。

谢谢

mysql> explain select * from udr where userid = '315533';
+----+-------------+-------+------+---------------+--------+---------+-------+-------+-------+
| id | select_type | table | type | possible_keys | key    | key_len | ref   | rows  | Extra |
+----+-------------+-------+------+---------------+--------+---------+-------+-------+-------+
|  1 | SIMPLE      | udr   | ref  | userid        | userid | 4       | const | 12738 |       |
+----+-------------+-------+------+---------------+--------+---------+-------+-------+-------+
1 row in set (0.02 sec)

iotop 报告重磁盘 io。我怀疑 mysql 正在将所有记录检索到内存中。

【问题讨论】:

  • 您有一个time 列但查询到datetime?
  • 使用explain select 并查看输出。可能有些索引没有创建或不工作
  • 用户315533返回多少条记录?
  • 把引擎换成MyISAM会不会更好?
  • 按照已经建议的方式执行EXPLAIN <your_query>,并以文本形式在您的问题中发布结果

标签: mysql


【解决方案1】:
SELECT time,upbytes,downbytes
    FROM udr
    WHERE userid = 315533 AND
    time BETWEEN '2014-01-01 14:35:28' AND '2014-01-02 14:35:28'

在此查询中,您将搜索两列,timeuserid。您确实在这两列上都有索引,但 MySQL 一次只能使用其中一个。

MySQL 将选择使用time-index 或userid 索引。如果选择userid,则需要检索12738行,导致查询时间过长。 MySQL然后会搜索检索到的数据以过滤掉time-column。

解决方案是在两列上都添加索引:

ALTER TABLE udr ADD KEY (`userid`, `time`);

这样,MySQL 可以同时搜索 useridtime,而无需先检索数据。

注意:创建新索引可能需要几分钟,请耐心等待。

【讨论】:

  • 不错的一个。但是仅使用 userid 的查询仍然需要几乎相同的时间。
  • 是的,因为它仍然需要超过 250MB。如果你用另一列限制结果,比如time,返回的行数会少得多,查询会运行得更快。如果您想要单个 userid 的所有行,则查询不能更快。
  • 如何获得 12738 行 = 250MB?这意味着每行是 20KB。
  • @SvetlinZarev 我自己有一个巨大的 InnoDB 表,可以查询多个列,使用正确的索引运行得非常快。为什么在这种情况下,当他更换引擎时,性能会提高这么多?也许这张桌子很旧而且磁盘上很乱?
  • 我不知道,这可能是一个错误或......一切。但是假设他有一个关于用户 ID 的索引并且用户 ID 是唯一的,那么 WHERE userid = 315533 语句必须返回 0 或 1 行,然后数据库应该检查时间列。由于 B-Tree 索引,这一行应该以与 logN 成比例的时间返回。也许由于某种原因,数据库没有使用索引?尝试“解释选择”,它可能会提示您出了什么问题
【解决方案2】:

尝试在timeuserid 中建立索引。您可以使用phpmyadmin 或sqlyog 轻松建立索引。

【讨论】:

  • 仅使用用户 ID 的查询花费几乎相同的时间。
  • 是的,因为中间和时间条件需要时间。在你的表中建立索引,它显然会减少时间。
【解决方案3】:

但是仅使用 userid 的查询仍然需要几乎相同数量的 时间。

你不能做更多。 你的硬件规格是什么? 我的配置是平均的,比你的高:

query_cache_size =  64 MiB
key_buffer =  128 MiB
max_allowed_packet  =  16M
thread_stack    =  294 Kb
thread_cache_size       = 128
query_cache_limit =  128 KiB

我建议使用 MariaDB / Percona 代替标准 MySQL,然后再尝试使用 MYISAM。他们和 Aria 一起进步很大......

【讨论】:

    猜你喜欢
    • 2021-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多