有人能帮忙优化一条SQL吗

qq_41866860 2020-12-10 09:51:11


SELECT ri.id, ri.report_id, ri.reason, ri.topic, ri.online_at
, ri.offline_at, ri.online_time, ri.gmt_create, ri.gmt_modified
FROM report_info ri
LEFT JOIN report r ON r.id = ri.report_id
WHERE r.device_name = ?
ORDER BY ri.id DESC
LIMIT 1
...全文
2054 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
冰思雨 2020-12-11
  • 打赏
  • 举报
回复
第一,楼主的SQL语句,为啥要用左连接呢,等值连接不是一样的效果吗?至少,我是这样理解的。而且,我感觉,这种情况下的等值连接比左连接的效率高。 第二,device_name 没有建立索引,所以,查找效率会比较低下。要么,查询条件添加一个product_id,要么,建立一个新的索引,device_name排第一位。 第三,要求是按照 offline_at 排序,取第一条记录。实际的SQL语句中,却是按照id排的顺序。

-- 创建新的索引,加快查找速度。
ALTER TABLE report ADD INDEX idx_report_device_name ON (device_name);
-- 查询语句,仅做参考。
SELECT ri.id, ri.report_id, ri.reason, ri.topic, ri.online_at, ri.offline_at, ri.online_time, ri.gmt_create, ri.gmt_modified
FROM report_info ri, report r 
WHERE r.id = ri.report_id AND r.device_name = ?
ORDER BY ri.offline_at DESC
LIMIT 1
先尝试一下我提供的代码,如果性能还是没有提升,可以考虑一下两种方案。 1. 使用 explain sql ,看看索引的使用情况,where 条件 和 order by 是否都使用上了索引,如果没有的话,调整一下索引即可。 2. 高并发的场景,一般不会用数据库来抗压力,会使用 redis 缓存来分担绝大部分的查询压力。(读远大于写的项目,尤为突出。) 最后,谈谈高并发场景的缓存使用,一般缓存会进行分级并设置数据的失效时长, 单机节点的应用程序内部会建立一级缓存, 然后,局域网内另选服务器部署redis建立二级缓存, 最后才是数据的查询操作。 一级缓存未命中(失配)时访问二级缓存,二级缓存未命中(失配)时访问数据库。 注意事项: 1. 通常缓存存储的是key-value数据。要学会缓存key-null数据来避免 缓存穿透。 2. 当缓存未命中时,向下一级缓存或者数据库获取数据的过程尽量使用互斥锁,避免 缓存击穿。 3. 缓存数据的失效时长,尽量设置成某一时间范围内的随机时长(如果存在系统配置信息,可以设置成永不过期),避免 缓存雪崩。
赵博林 2020-12-11
  • 打赏
  • 举报
回复
很好的问题,mark
ykcombaty 2020-12-11
  • 打赏
  • 举报
回复
引用 5 楼 Amin已经存在了 的回复:
你的目的是:根据device_name获得report_info表里offline_at时间为最新的一条记录。 如果不差分sql语句的话,把deviceName和reportId加索引,查询的信息只查询自己用到的。但是我不建议这么做,我建议,你把整个sql用业务拆分下,你先单独通过查询条件device_name查询A表,拿到reportId,之后通过reportid查询表,拿到最新数据。分两步走,在这两步中,如果业务量很大,可以加入缓存等技术
同意噢。数据库干的太多的活 ,可以分一些给内存,另外,要注意索引、小表驱动大表等要点。
xiaoxiangqing 2020-12-11
  • 打赏
  • 举报
回复
你要看一下数据多不多?
冰思雨 2020-12-11
  • 打赏
  • 举报
回复
我提供的SQL语句中,问号“?”要改成半角的(英文输入状态下)的问号"?"
  • 打赏
  • 举报
回复
你的目的是:根据device_name获得report_info表里offline_at时间为最新的一条记录。 如果不差分sql语句的话,把deviceName和reportId加索引,查询的信息只查询自己用到的。但是我不建议这么做,我建议,你把整个sql用业务拆分下,你先单独通过查询条件device_name查询A表,拿到reportId,之后通过reportid查询表,拿到最新数据。分两步走,在这两步中,如果业务量很大,可以加入缓存等技术
  • 打赏
  • 举报
回复
select ri.* from report_info ri inner join ( select id from report where device_name = ? ) r on ri.report_id=r.id order by ri.id desc limit 1
qq_41866860 2020-12-10
  • 打赏
  • 举报
回复
现在并发高越高的情况下耗时就越久,30个并发就走了5秒了
qq_41866860 2020-12-10
  • 打赏
  • 举报
回复
SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;
-- ------------------------------ Table structure for report-- ----------------------------DROP TABLE IF EXISTS `report`;CREATE TABLE `report` ( `id` int(11) NOT NULL AUTO_INCREMENT, `event` varchar(16) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `product_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `device_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `report_date` date NOT NULL, `gmt_create` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, `gmt_modified` timestamp(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE, INDEX `idx_default`(`product_id`, `device_name`, `report_date`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 35630 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;








SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS = 0;
-- ------------------------------ Table structure for report_info-- ----------------------------DROP TABLE IF EXISTS `report_info`;CREATE TABLE `report_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `report_id` int(11) NOT NULL, `reason` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL, `topic` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `online_at` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, `offline_at` timestamp(0) NULL DEFAULT NULL, `online_time` int(11) NULL DEFAULT NULL, `gmt_create` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, `gmt_modified` timestamp(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE, INDEX `idx_default`(`offline_at`, `online_time`) USING BTREE) ENGINE = InnoDB AUTO_INCREMENT = 161001 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
qq_41866860 2020-12-10
  • 打赏
  • 举报
回复
想根据device_name获得report_info表里offline_at时间为最新的一条记录
Forevermark993 2020-12-10
  • 打赏
  • 举报
回复
explain sql 先查查原因
戎码一生灬 2020-12-10
  • 打赏
  • 举报
回复
如果可以的话,这俩表数据落库的时候,也顺便往redis缓存一下最新数据

67,538

社区成员

发帖
与我相关
我的任务
社区描述
J2EE只是Java企业应用。我们需要一个跨J2SE/WEB/EJB的微容器,保护我们的业务核心组件(中间件),以延续它的生命力,而不是依赖J2SE/J2EE版本。
社区管理员
  • Java EE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧