【发布时间】:2017-04-24 14:15:10
【问题描述】:
我必须创建一个 cron 作业,这本身很简单,但因为它会每分钟运行一次,所以我担心性能。我有两张表,一张有用户名,另一张有关于他们网络的详细信息。大多数时候,一个用户只属于一个网络,但理论上他们可能属于更多网络,但即使这样也很少,可能是两个或三个。因此,为了减少 JOIN 的数量,我将由| 分隔的网络 ID 保存在用户表的一个字段中,例如
|1|3|9|
(为这个问题简化的)用户表结构是
TABLE `users` (
`u_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
`userid` VARCHAR(500) NOT NULL UNIQUE,
`net_ids` VARCHAR(500) NOT NULL DEFAULT '',
PRIMARY KEY (`u_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
(也简化的)网络表结构是
CREATE TABLE `network` (
`n_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE,
`netname` VARCHAR(500) NOT NULL UNIQUE,
`login_time` DATETIME DEFAULT NULL,
`timeout_mins` TINYINT UNSIGNED NOT NULL DEFAULT 10,
PRIMARY KEY (`n_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
发生超时时我必须发送警告,我的查询是
SELECT N.netname, N.timeout_mins, N.n_id, U.userid FROM
(SELECT netname, timeout_mins, n_id FROM network
WHERE is_open = 1 AND notify = 1
AND TIMESTAMPDIFF(SECOND, TIMESTAMPADD(MINUTE, timeout_mins, login_time), NOW()) < 60) AS N
INNER JOIN users AS U ON U.net_ids LIKE CONCAT('%|', N.n_id, '|%');
我将 N 设为子查询以减少加入的行数。但是我想知道添加以 u_id 和 n_id 作为列的第三个表是否会更快,从用户中删除 net_ids 列,然后对所有三个表进行连接?因为我读到使用 LIKE 会减慢速度。
在这种情况下,最有效的查询是什么?一个 JOIN 和一个 LIKE 还是两个 JOIN?
附:我做了一些实验,使用两个 JOIN 的初始值高于使用一个 JOIN 和一个 LIKE。但是,重复运行相同的查询似乎会加快速度,我怀疑某些东西缓存在某处,无论是在我的应用程序还是数据库中,并且两者都具有可比性,所以我觉得这个数据并不令人满意。根据我所阅读的内容,这也与我的预期相矛盾。
我用过这张桌子:
TABLE `user_net` (
`u_id` BIGINT UNSIGNED NOT NULL,
`n_id` BIGINT UNSIGNED NOT NULL,
INDEX `u_id` (`u_id`),
FOREIGN KEY (`u_id`) REFERENCES `users`(`u_id`),
INDEX `n_id` (`n_id`),
FOREIGN KEY (`n_id`) REFERENCES `network`(`n_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
这个查询:
SELECT N.netname, N.timeout_mins, N.n_id, U.userid FROM
(SELECT netname, timeout_mins, n_id FROM network
WHERE is_open = 1 AND notify = 1
AND TIMESTAMPDIFF(SECOND, TIMESTAMPADD(MINUTE, timeout_mins, login_time), NOW()) < 60) AS N
INNER JOIN user_net AS UN ON N.n_id = UN.n_id
INNER JOIN users AS U ON UN.u_id = U.u_id;
【问题讨论】:
-
:-( 不要那样做。
-
检查执行计划。不要猜测。虽然,
LIKE '%something%'总是很慢 - 没有办法使用带有这样一个字符串的索引,这意味着将扫描 每一行 行 -
不要使用我目前的方法?我意识到这不是理想的设计,但我主要关心的是减少此查询的时间。
-
顺便说一句,如果您
net_ids字段包含一个带有分隔值的字符串,那么您有一个严重的(实际上是癌症中的终端)设计错误 - 您通过在单个单元格中存储多个值来破坏 1NF .使用单独的表格 -
如何查看执行计划?我无权访问 phpMyAdmin。我的客户没有给我 cPanel 访问权限。我一直在使用自己制作的简单表单来运行我必须执行的查询,例如创建表。
标签: mysql performance join sql-like