【问题标题】:Terrible and slow query可怕而缓慢的查询
【发布时间】:2013-09-02 23:23:05
【问题描述】:

我在查询时遇到了一些速度问题,它显示了我的数据库中的用户列表。 我想显示具有交通信息的用户列表以及与用户一起工作的最后一位员工。

数据库看起来像这样:

用户表(包含用户信息):

CREATE TABLE `users` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `ip` tinytext NOT NULL,
 `name` varchar(64) NOT NULL,

... some other fields

 PRIMARY KEY (`id`),
 UNIQUE KEY `name` (`name`),
 KEY `ip` (`ip`(15)) USING BTREE,
)

users_trf 表(包含有关用户流量的信息;uid - users 表中的用户 ID):

CREATE TABLE `users_trf` (
 `uid` int(11) unsigned NOT NULL,
 `uip` varchar(15) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL,
 `in` bigint(20) NOT NULL DEFAULT '0',
 `out` bigint(20) NOT NULL DEFAULT '0',
 `test` tinyint(4) NOT NULL,
 UNIQUE KEY `uid` (`uid`),
 KEY `test` (`test`)
)

拥有所有员工名单的员工:

CREATE TABLE `employees` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `full_name` varchar(16) NOT NULL,
 PRIMARY KEY (`id`)
)

和记录表,我在其中存储有关员工与客户端所做的工作的数据(uid - 来自用户表的客户端 ID,中间 - 来自员工表的员工 ID):

CREATE TABLE `employees_log` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `uid` int(10) unsigned NOT NULL,
 `mid` int(10) unsigned NOT NULL,
 `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 `note` text NOT NULL,
 PRIMARY KEY (`id`)
)

我的查询:

SELECT SQL_CALC_FOUND_ROWS *
FROM users u
LEFT JOIN users_trf t ON u.id = t.uid
LEFT JOIN (

SELECT e2.full_name, e1.uid, e1.mid AS moid
FROM employees_log e1
LEFT JOIN employees e2 ON e1.mid = e2.id
WHERE NOT
EXISTS (

SELECT *
FROM employees_log e3
WHERE e1.uid = e3.uid
AND e1.id < e3.id
)
) e ON e.uid = u.id
LIMIT 0 , 50

它的工作速度很慢,我认为这是这个子查询的原因(我正在尝试选择最后一位与客户合作的员工):

SELECT e2.full_name, e1.uid, e1.mid AS moid
FROM employees_log e1
LEFT JOIN employees e2 ON e1.mid = e2.id
WHERE NOT
EXISTS (

SELECT *
FROM employees_log e3
WHERE e1.uid = e3.uid
AND e1.id < e3.id
)

是否可以加快我的查询速度?

更新: 我添加了索引ALTER TABLE employees_log ADD INDEX ( uid, id );,查询速度提高了 2 倍,但我可以让它更快吗?

+----+--------------------+------------+--------+---------------+---------+---------+-------------+-------+--------------------------+
| id | select_type        | table      | type   | possible_keys | key     | key_len | ref         | rows  | Extra                    |
+----+--------------------+------------+--------+---------------+---------+---------+-------------+-------+--------------------------+
|  1 | PRIMARY            | u          | ALL    | NULL          | NULL    | NULL    | NULL        | 12029 |                          |
|  1 | PRIMARY            | t          | eq_ref | uid           | uid     | 4       | bill.u.id   |     1 |                          |
|  1 | PRIMARY            | <derived2> | ALL    | NULL          | NULL    | NULL    | NULL        |  2239 |                          |
|  2 | DERIVED            | e1         | ALL    | NULL          | NULL    | NULL    | NULL        |  2288 | Using where              |
|  2 | DERIVED            | e2         | eq_ref | PRIMARY       | PRIMARY | 4       | bill.e1.mid |     1 |                          |
|  3 | DEPENDENT SUBQUERY | e3         | ref    | PRIMARY,uid   | uid     | 4       | bill.e1.uid |     1 | Using where; Using index |
+----+--------------------+------------+--------+---------------+---------+---------+-------------+-------+--------------------------+

【问题讨论】:

  • 请发布您的查询的解释 - 否则,它的猜测工作......
  • @NevilleK,我在帖子中添加了解释

标签: mysql


【解决方案1】:

首先,我认为您必须向自己解释为什么要使用 int 和 bigint。你真的期望这么多数据吗?尝试使用 smallint 或 mediumint,它们需要更少的内存并且速度更快。如果您使用 mediumint 和 smallint 作为无符号,它们可以有一个相当大的值,看看:http://dev.mysql.com/doc/refman/5.0/en/integer-types.html

其次,你需要将某个字段组合成一个键:

ALTER TABLE  `employees_log ` ADD INDEX (  `uid` ,  `id` ) ;

【讨论】:

  • 我在这个BIGINT字段中存储了流量,以字节为单位,现在最大的是8768544565747
  • 谢谢,索引帮助加快了 50% 的查询速度
【解决方案2】:

如果您正在创建一个新的 MySQL 表,您可以使用 INDEX 术语指定要索引的列。索引是您可以在 MySQL 表上启用以提高性能的额外功能 http://www.databasejournal.com/features/mysql/article.php/1382791/Optimizing-MySQL-Queries-and-Indexes.htm
http://www.tutorialspoint.com/mysql/mysql-indexes.htm 查看这个它给了你很多想法..

【讨论】:

  • 谢谢你,很好的文章
【解决方案3】:

您的目标是尝试加入日志表中该用户的最后一名员工的日志(至少基于密钥),也许只是尝试使用= &lt;subquery&gt; 而不是NOT EXISTS

SELECT e2.full_name, e1.uid, e1.mid AS moid
FROM employees_log e1
LEFT JOIN employees e2 ON e1.mid = e2.id
WHERE e1.id = (
  SELECT MAX(e3.id)
  FROM employees_log e3
  WHERE e1.uid = e3.uid
)

【讨论】:

  • 这行得通,但我发现这个查询和我的原始查询没有速度差异
【解决方案4】:

考虑在 employees_log 的 MID 和 UID 列上添加索引 - 解释表明此连接未使用索引。

像这样:在 employees_log (mid, uid) 上创建索引复合

【讨论】:

  • 我会在星期一检查它,现在不能这样做,对不起它是周末:(
  • 我添加了,mysql没有使用,EXPLAIN输出没有改变
猜你喜欢
  • 1970-01-01
  • 2011-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 2020-06-10
  • 2012-01-15
相关资源
最近更新 更多