表一 data_detail
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for data_detail
-- ----------------------------
DROP TABLE IF EXISTS `data_detail`;
CREATE TABLE `data_detail` (
`id` bigint(20) UNSIGNED NOT NULL,
`content` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '文本内容',
`create_by` int(11) NULL DEFAULT NULL COMMENT '创建人',
`data_set_id` int(11) NOT NULL COMMENT '数据集编号',
`size` double(255, 0) NULL DEFAULT NULL COMMENT '文件大小',
`status` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '0:未标注 2:人工标注 1:自动标注',
`source` tinyint(3) UNSIGNED NULL DEFAULT 2 COMMENT '数据来源:1:上传; 2:手动创建; 3:运营管理改正;',
`mkey` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '',
`remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '备注,业务系统用',
`origin_id` bigint(20) UNSIGNED NOT NULL COMMENT '基于那一条初始数据变化过来的',
`create_time` datetime(0) NULL DEFAULT NULL COMMENT '创建时间',
`update_time` datetime(0) NULL DEFAULT NULL COMMENT '更新时间',
`version_id` int(11) NULL DEFAULT NULL,
`update_by` int(11) NULL DEFAULT NULL COMMENT '更新人',
PRIMARY KEY (`id`, `data_set_id`) USING BTREE,
INDEX `status_data_set_id`(`status`, `data_set_id`) USING BTREE,
INDEX `id`(`id`) USING BTREE,
INDEX `create_time`(`create_time`) USING BTREE,
INDEX `indexid`(`create_time`, `id`) USING BTREE
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '数据详情内容' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
表二 data_detail_delete
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for data_detail_delete
-- ----------------------------
DROP TABLE IF EXISTS `data_detail_delete`;
CREATE TABLE `data_detail_delete` (
`data_detail_id` bigint(20) UNSIGNED NOT NULL COMMENT '数据集详情id',
`origin_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '最原始的id\r\n最原始的数据详情id',
`version_id` int(11) NULL DEFAULT NULL COMMENT '版本id',
`data_set_id` int(11) NOT NULL COMMENT '数据集id',
PRIMARY KEY (`data_detail_id`, `data_set_id`) USING BTREE,
INDEX `version_data_set_id_index`(`version_id`, `data_set_id`) USING BTREE COMMENT '索引'
) ENGINE = MyISAM CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
表三 data_tag_reference
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for data_tag_reference
-- ----------------------------
DROP TABLE IF EXISTS `data_tag_reference`;
CREATE TABLE `data_tag_reference` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
`detail_id` bigint(20) UNSIGNED NULL DEFAULT NULL COMMENT '数据详情id',
`type` tinyint(3) UNSIGNED NULL DEFAULT NULL COMMENT '表类型:1 ,类型1 ,2,类型2, 3,类型3',
`data_set_id` int(11) NULL DEFAULT NULL COMMENT '数据集id',
`tag_id` int(11) NULL DEFAULT NULL COMMENT '标签id',
`tag_set_id` int(11) NULL DEFAULT NULL COMMENT '标签库id',
PRIMARY KEY (`id`) USING BTREE,
INDEX `detail_id`(`detail_id`) USING BTREE,
INDEX `isUesd`(`type`, `tag_id`, `tag_set_id`) USING BTREE,
INDEX `detail_id_2`(`detail_id`, `data_set_id`) USING BTREE,
INDEX `tagid`(`tag_id`, `detail_id`, `data_set_id`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 58544606 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
需要优化的sql
SELECT
DISTINCT(dd.id), dd.*
FROM
data_detail dd
straight_join data_tag_reference dtr ON dd.id = dtr.detail_id
AND dd.data_set_id = dtr.data_set_id
WHERE
1024 >= dd.version_id
AND dd.data_set_id = 253
AND dd.id NOT IN ( SELECT data_detail_id FROM data_detail_delete WHERE 1002 >= version_id AND data_set_id = 253 )
AND dtr.tag_id in(-94110690 )
AND `content` like concat ('%','一' ,'%')
ORDER BY
dd.create_time Desc
LIMIT 0,
50
三个表的数据量都比较大。
group by id 和order by create_time DESC这两个字段的冲突,不好解决。同时用了 group by和order by这两个字段,会使用filesort文件排序 ,全表排序,导致时间至少在4-5秒,如果没有order by create_time,时间只用了0.03s,在mysql8.0中测试没有这个冲突,会使用Backward index scan降序索引,就会非常快。系统用的是mysql5.7只能找其他优化方法。数据集详情又必须有按照创建时间降序排序这个需求,sql的这个order by也不能去掉,在这里花了不少时间,加各种索引都试过。
group by id是为了去重。
在mysql8里面,可以用distinct(id), 而且用到了 Backward index scan,mysql 8的这个新特性。速度就非常快,但是公司又不能用mysql8。MariaDb10.5试过,同样的语句,索引也一样, mysql8 里运行了0.03s,mariaDb用了7s,我看解释里面区别就是这个 Backward index scan。除了mysql8 ,其他数据库都是用到了filesort。
各位大神,看看有没有办法能优化一下这个句子。
主要是索引的添加。
其中最重要的核心部分,造成卡的地方就是
ORDER BY
dd.create_time Desc
DISTINCT(dd.id)
还有limit 50.
这三个条件是必须的,核心需求。
其他where的筛选好像对速度影响不大,有影响可以砍掉
应要求执行计划 mysql 5.7的。
下面是mysql8.0的,多了个 Backward index scan
能不能对时间字段加索引呢?没有索引的order by是比较慢
您好,我是有问必答小助手,你的问题已经有小伙伴为您解答了问题,您看下是否解决了您的问题,可以追评进行沟通哦~
如果有您比较满意的答案 / 帮您提供解决思路的答案,可以点击【采纳】按钮,给回答的小伙伴一些鼓励哦~~
ps:问答VIP仅需29元,即可享受5次/月 有问必答服务,了解详情>>>https://vip.csdn.net/askvip?utm_source=1146287632
执行计划能贴一下吗,我个人觉得你的分析不准确,分组和排序冲突,这怎么理解,我没明白...
非常感谢您使用有问必答服务,为了后续更快速的帮您解决问题,现诚邀您参与有问必答体验反馈。您的建议将会运用到我们的产品优化中,希望能得到您的支持与协助!
速戳参与调研>>>https://t.csdnimg.cn/Kf0y
你好,我也遇到了相同的问题
有个分页查询,主表和从表是一对多关系,主从表都有很多查询条件
最后发现可以采用如下模式,经测试,能达到500ms效果,望采纳,谢谢
SELECT
distinct s.*
,
(select max(policy_num) from policy where insurance_id = s.id),
(select max(applicant) from policy where insurance_id = s.id),
(select max(policy_num) from policy where insurance_id = s.id),
(select max(company_name) from policy where insurance_id = s.id),
(select max(insurant) from policy where insurance_id = s.id),
(select max(insurant_phone) from policy where insurance_id = s.id)
FROM insurance
AS s
ORDER BY s.payment_time desc
limit 0,10000
;