百亿级sql优化

sql年年有,年年各不同,今天我们要说的是一把 360s+ ------ 2.8s 的sql优化

要实现的功能很简单,业务员通过Excel给了我一批角色id,大约四万个,我需要通过数据库查询出这些角色所在的区服和角色名称去实现其他用途。 看了一下角色现在有160w+数据。
角色表中 恰好包含 role_id,game_id, user_id的联合索引,正好有我们需要的角色id,那这么查询就快得多
刚开始的思路如下,我先在数据库中建立一张临时使用的数据表,命名为uid,其只包含一列主键id(类型直接设置为bigint,用数字做主键查询更快,联想equals算法),我将四万个角色id写入表中。
我以这张表为主表,通过左连接可以直接查询到我需要的区服和角色名称,实现sql如下,看起来很简单,但实际查询时用了六分钟还没有结果,开玩笑、B+树是假的吗?

SELECT
	u.id,
	bc.role_id,
	bc.game_id,
	bc.user_id,
	bc.role_name,
	bc.game_server_id 
FROM
	`uid` u
	LEFT JOIN ( SELECT role_id,game_id, user_id, role_name, game_server_id FROM `b_gm_dev_create` GROUP BY role_id) bc ON u.id = bc.role_id 
GROUP BY
	u.id

按理说u.id主键自带索引。 bc.role_id也有索引,emm,那不是相当快的,而且左连接是基于查询b_gm_dev_create的结果集的,对b_gm_dev_create的查询条件都包含索引,理应很快。那这是为什么呢?难道是包含了不带索引的列走了全表查询?不服输的我将所有不包含索引的列去除又重试了一下

SELECT
	u.id,
	bc.role_id,
	bc.game_id,
	bc.user_id
FROM
	`uid` u
	LEFT JOIN ( SELECT role_id,game_id, user_id, role_name, game_server_id FROM `b_gm_dev_create` GROUP BY role_id) bc ON u.id = bc.role_id 
GROUP BY
	u.id

emm,同上一样,还是出不了结果???那是因为bc表的select列放到了u.id后导致的吗?再改改试试

SELECT
	bc.role_id,
	bc.game_id,
	bc.user_id,
	u.id
FROM
	`uid` u
	LEFT JOIN ( SELECT role_id,game_id, user_id, role_name, game_server_id FROM `b_gm_dev_create` GROUP BY role_id) bc ON u.id = bc.role_id 
GROUP BY
	u.id

嗯???还是跑了好久没有结果, 我直接做了一次角色表的查询

SELECT role_id,game_id, user_id, role_name, game_server_id FROM `b_gm_dev_create` GROUP BY role_id

160W+数据用时两秒。。EMM,炸裂。不就是作为从表了吗怎么就这么拖后腿,mysql你不爱我了吗?

试试把角色表作为主表,那么匹配不到 u.id的此列就为空,去除u.id为空的就能获得我们需要的值。sql如下

SELECT
	bc.game_server_id ,
	bc.role_name
FROM
	`b_gm_dev_create` bc
	LEFT JOIN uid u ON bc.role_id = u.id 
WHERE
	u.id IS NOT NULL

用时 2.8秒 4w条匹配数据就出来了 这么快的速度也必然是走了索引,聚簇索引真香(狗头保命)

接下来分析下为什么会这样

直接执行sql

SELECT role_id,game_id, user_id, role_name, game_server_id FROM `b_gm_dev_create` GROUP BY role_id

速度很快,也就是说如果先去处理角色表,获取角色表的结果集,这个速度会快得多。那也就是说我们以uid表作为主表执行左连接时。在mysql的查询计划里对角色表的处理是放在uid表之后的,这回导致对角色表的连接查询会反复回表,性能极其低下(话说mysql自动的查询优化还是靠不住a,还得靠我国辛劳的sql攻城狮),而sql优化中也有一条准则就是先处理较大的数据集一般会提高性能,毕竟从源头缩小结果集对于之后的查询会十分友好。而之后以角色表为主表的查询在mysql的查询计划中角色表优先被处理,且由于连接条件都有索引,那速度当然杠杠的,完全取到内存的数据互相关联查询当然快得很。一句话,这feel倍儿爽。

你可能感兴趣的:(数据库)