mysql - 获取用户在队列表中的位置太慢

标签 mysql mariadb

我有一个如下所示的 MariaDB 表:

+--------+--------+--------+---------------------+
| realm  |  key2  | userId |        date         |
+--------+--------+--------+---------------------+
|    AB3 |    123 |      1 | 2017-08-04 17:30:00 |
|    AB3 |    124 |      1 | 2017-08-04 17:30:00 |
|    AB3 |    125 |      1 | 2017-08-04 17:30:00 |
|    XY7 |     97 |      2 | 2017-08-04 17:35:00 |
|    XY7 |     98 |      2 | 2017-08-04 17:35:00 |
|    XY7 |     99 |      2 | 2017-08-04 17:35:00 |
|    AB3 |    110 |      3 | 2017-08-04 17:40:00 |
|    AB3 |    111 |      3 | 2017-08-04 17:40:00 |
+--------+--------+--------+---------------------+

PRIMARY_KEY (realm, key2)
INDEX (realm, userId)
INDEX (date)

该表作为某种队列来处理用户操作。基本上,服务器总是从该表中获取最旧的数据,对其进行处理并将其从该表中删除。每个领域都有自己的服务器处理此队列。

现在我想找出用户在该领域的队列中的位置。因此,使用上面的示例,当我请求领域“AB3”中 userId 3 的位置时,我希望获得结果 2,因为只有一个其他用户 (userId 1) 需要提前处理领域AB3。

(行 key2 可能在此示例中不相关。我只包含它,因为它是主键的一部分,这可能使其与寻找良好的解决方案相关)

这是 SQL 架构:

CREATE TABLE `queue` (
  `realm` varchar(5) NOT NULL,
  `key2` int(10) UNSIGNED NOT NULL,
  `userId` int(10) UNSIGNED NOT NULL,
  `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

INSERT INTO `queue` (`realm`, `key2`, `userId`, `date`) VALUES
('AB3', 110, 3, '2017-08-04 17:40:00'),
('AB3', 111, 3, '2017-08-04 17:40:00'),
('AB3', 123, 1, '2017-08-04 17:30:00'),
('AB3', 124, 1, '2017-08-04 17:30:00'),
('AB3', 125, 1, '2017-08-04 17:30:00'),
('XY7', 97, 2, '2017-08-04 17:35:00'),
('XY7', 98, 2, '2017-08-04 17:35:00'),
('XY7', 99, 2, '2017-08-04 17:35:00');

ALTER TABLE `queue`
  ADD PRIMARY KEY (`realm`,`key2`),
  ADD KEY `ru` (`realm`,`userId`) USING BTREE,
  ADD KEY `date` (`date`);

我想出了这个查询,它似乎有效,但在包含 10,000,000 个条目的表上速度相当慢(约 3 秒):

SELECT (COUNT(DISTINCT `realm`, `userId`)+1) `position`
FROM `queue`
WHERE `realm` = 'AB3'
AND `date` < (
  SELECT `date`
  FROM `queue`
  WHERE `realm` = 'AB3' AND `userId` = 3
  GROUP BY `realm`, `userId`
)

SQL fiddle :http://sqlfiddle.com/#!9/fb04fd/9/0

此查询的

EXPLAIN EXTENDED:

+----+-------------+-------+-------------+-----------------+------------+---------+-------+---------+----------+------------------------------------------+--+
| id | select_type | table |    type     |  possible_keys  |    key     | key_len |  ref  |  rows   | filtered |                  Extra                   |  |
+----+-------------+-------+-------------+-----------------+------------+---------+-------+---------+----------+------------------------------------------+--+
|  1 | PRIMARY     | queue | ref         | PRIMARY,ru,date | PRIMARY    |     767 | const | 5266123 |   100.00 | Using where                              |  |
|  2 | SUBQUERY    | queue | index_merge | PRIMARY,ru      | ru,PRIMARY | 771,767 |       |     496 |    75.00 | Using intersect(ru,PRIMARY); Using where |  |
+----+-------------+-------+-------------+-----------------+------------+---------+-------+---------+----------+------------------------------------------+--+

您知道如何优化此查询,以便在包含 10,000,000 个条目的表上运行得更快吗?


在此表上运行的其他查询:

SELECT `m`.*
FROM `queue` `m`
JOIN (
    SELECT `m`.*
    FROM `queue` `m`
    WHERE `m`.`realm` = ?
    ORDER BY `date` ASC
    LIMIT 1
) `mm` ON `m`.`realm` = `mm`.`realm` AND `m`.`userId` = `mm`.`userId`;

DELETE FROM `queue` WHERE `realm` = ? AND `userId` = ?;

如何优化我的索引?

最佳答案

我感觉表 DDL 有问题。不管怎样,我会重写你的查询:

SELECT (COUNT(DISTINCT `userId`)+1) `position`
FROM `queue`
WHERE `realm` = 'AB3'
    AND `date` < (
        SELECT min(`date`)
        FROM `queue`
        WHERE `realm` = 'AB3' AND `userId` = 3
    )

也许这个查询有一个非常具体的索引,例如:

index (realm, date)

您可以尝试使用sheety索引

index (realm, date, userId)  

但甚至不确定它会比前一个更快。

关于mysql - 获取用户在队列表中的位置太慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45518778/

相关文章:

MySql 查询 3 个不同的表

php - 删除多个复选框上的行后未获取 $_GET 的值?

php - mysql无缓冲查询锁定不锁定

mysql - 飞行路线 | MariaDb - 无法执行条件 block

php - MySQL 1253 COLLATION 错误 PHP

c# - 连接 Mysql 与 Visual Studio 2015 C#

mysql - 如果表存在则执行某些操作

java - 为 jdbc :mysql 在 mariadb 中禁用持久连接

PHP 接口(interface) mysql() 不工作,但 mysqli() 工作;为什么?

mysql - MariaDB View 不起作用,但语句起作用