我有两个定义如下的表:
CREATE TABLE `a` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cid` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`data` varchar(1024) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '',
`update_time` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(0),
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 150 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
a中有10k行,b中有200k行,所有数据都是由随机函数生成的。下面是一个示例:
151 8VE6BU06 8VE6BU06 2019-09-12 23:07:39
这是三个测试,
1。案例1耗时2.889秒
SELECT cid FROM `a` WHERE a.cid not in (select b.cid from b);
execution plan
1 PRIMARY a ALL 10094 Using where
2 SUBQUERY b ALL 199826
2。案例2花费628.699s
delete from `a` WHERE a.cid not in (select b.cid from b);
execution plan
1 PRIMARY a ALL 10094 Using where
2 DEPENDENT SUBQUERY b ALL 199826 Using where
3。案例3的费用为0.036秒
alter table b add index cid(cid);
delete from `a` WHERE a.cid not in (select b.cid from b);
execution plan
1 PRIMARY a ALL 10094 Using where
2 DEPENDENT SUBQUERY b index_subquery cid cid 302 func 1 Using index
问题
MySQL版本: 5.6.20 innodb
表b中的行数据如下:
151 8VE6BU06 8VE6BU06 2019-09-12 23:07:39
答案 0 :(得分:4)
def self.from_token_request(request)
email = request.params["auth"] && request.params["auth"]["email"]
confirmation_email = request.params["auth"] && request.params["auth"]["confirmation_email"]
self.find_by(email: email, confirmation_email: confirmation_email)
end
相比,解析和优化def auth_params
params.require(:auth).permit(:email, :password, :confirmation_email)
end
和DELETE
的方式不同(不那么好)。更高的版本(5.7?或8.0)效果更好。UPDATE
必须创建撤消记录,以防SELECT
中途崩溃;相对于选择而言,这是非常昂贵的。DELETE
怎么说DELETE
和EXPLAINs
。这意味着“对于一个表中的每一行,它将扫描另一表中的所有行”。第三个解释是由于ALL
,速度提高了几个数量级。ALL
的性能通常很差-就像在完整扫描中一样。INDEX
而非NOT IN ( SELECT ... )
方法将其更改为“多表DELETE
”。LEFT JOIN ... IS NULL
太小而无法容纳IN
的全部,这将导致大量的I / O,因此查询2的时间很长。innodb_buffer_pool_size
和b
的平均大小,进一步讨论I / O需求是不切实际的。答案 1 :(得分:1)
这些真的以秒为单位进行测量吗?对于中等大小的表上的这种简单查询,这似乎非常。
也就是说,对于相同的数据,通常DELETE
比SELECT
需要更长的时间。数据库引擎需要确保不破坏任何外键引用并更新索引等。此行为看起来很正常。
答案 2 :(得分:0)
在@shadow评论后,读取比写入/删除快。
请参阅https://dev.mysql.com/doc/refman/5.5/en/subquery-optimization.html
索引
索引将为您带来出色的性能。
为简单起见,索引就像文档的page0。
Page0 index
Mysql p1
Oracle p2
...
Postgresql p100
Page1
Some looooooong Mysql material
Page2
Some looooooong Oracle material
...
Page100
Some looooooong Postgresql material
按索引阅读
在page0中找到密钥所需的时间相对较短。例如,在索引中找到postgresql并转到第100页之后,这种方法比读取数百页要快得多。
删除索引
您只能删除page0索引中的postgresql。 您不必删除page100中的所有内容。
有关更多信息,请参阅 How does database indexing work?
答案 3 :(得分:0)
我没有“声誉”级别来添加评论,因此添加了回复-除了上面@John所说的之外,Markus Winand的"Use The Index, Luke"可能对您有用。 / p>