最初问题的背景是这样: * 例如对某个客户的报表生成需求,需要查询该客户在特定时间范围内的账单明细 为了简化说明,下面忽略连接查询,则可能的sql如下: select out_trade_no, payer_id, amount, status, gmt_create from order where merchant_id=123 and gmt_create between #{start} and #{end} order by gmt_create desc; 那么至少会需要一个"(merchant_id, gmt_create)"这样的一个多列索引。 此时因为要查询的字段比较多,所以不可能创建一个很长的多列索引来避免回表查询。而按照我的理解,这样的sql只能在二级索引上查到一条id就回表查询一次,如果gmt_create的范围拉的比较长(比如1个月),则会出现较多的随机IO。 一个能想到的可能优化是通过增加每页可以读取的数据来提高查询效率——延迟关联,那么将sql改为如下: select o.out_trade_no, o.payer_id, o.amount, o.status, o.gmt_create from order as o inner join ( select id from order where merchant_id=123 and gmt_create between #{start} and #{end} ) as sub using(id) order by o.gmt_create desc; 应该是可以进一步提高效率的。 不过最近我发现有些公司会直接使用ES来存储订单/明细表的数据,然后将类似这样的查询(例如报表需求)转发到es上执行,我想知道这样可以进一步提高查询效率吗?还是因为存在别的需求共同导致他们选择了es来代替这类sql查询?
SELECT ad.id, d.device_id, d.d_id AS variable_id, d.d_name, d.oper_type, d.d_type, d.d_decimal AS 'decimal', d.data_prot_param, ad.tag, ad.modbus_reg_addr, ad.modbus_area FROM box_api_data ad LEFT JOIN box_data_info d ON d.d_id = ad.variable_id WHERE ad.unique_code = '7000224061716030893' AND ad.topic_id = 572137887207493 AND d.unique_code = '7000224061716030893' 这个sql查询要6s多,但是我两张表数据量都不是很大呀。box_api_data目前40000条,box_data_info目前10006条。基本都是比较少的,这么个数据量连接查询居然干到了6s,是我sql有问题吗?目前两张表都没有索引。 CREATE TABLE `box_data_info` ( `id` int(11) NOT NULL AUTO_INCREMENT, `unique_code` varchar(50) NOT NULL COMMENT '所属编号', `device_id` int(11) NOT NULL COMMENT '所属设备', `d_id` int(11) NOT NULL COMMENT '变量标识', `d_name` varchar(128) NOT NULL COMMENT '变量名称', `oper_type` int(11) NOT NULL COMMENT '操作类型(0:只读,1:只写,2:读写)', `d_type` int(11) NOT NULL COMMENT '数据类型', `unit` varchar(30) DEFAULT NULL COMMENT '变量单位', `d_decimal` int(11) DEFAULT '0' COMMENT '小数位数', `min_range` varchar(20) DEFAULT NULL COMMENT '最小量程', `max_range` varchar(20) DEFAULT NULL COMMENT '最大量程', `r_formula` varchar(156) DEFAULT NULL COMMENT '读公式', `w_formula` varchar(156) DEFAULT NULL COMMENT '写公式', `d_status` int(11) DEFAULT NULL COMMENT '变量状态 0:离线,1:在线', `is_store` int(11) DEFAULT '0' COMMENT '是否存储', `data_prot_param` varchar(1000) DEFAULT NULL COMMENT '特殊配置', `is_custom` int(11) NOT NULL DEFAULT '0' COMMENT '是否是自定义变量(0:不是,1:是)', `trans_modbus_param` varchar(1000) DEFAULT NULL COMMENT '转换Modbus协议参数', `remark` varchar(256) DEFAULT NULL COMMENT '备注', `data_index` int(11) DEFAULT NULL COMMENT '数据索引', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=848295 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='点表'; CREATE TABLE `box_api_data` ( `id` int(11) NOT NULL AUTO_INCREMENT, `topic_id` bigint(20) DEFAULT NULL COMMENT '主题id', `variable_id` int(11) DEFAULT NULL COMMENT '数据标识', `device_id` int(11) DEFAULT NULL COMMENT '设备id', `tag` varchar(127) DEFAULT NULL COMMENT '数据标签', `modbus_area` varchar(10) DEFAULT NULL COMMENT 'modebus区域', `modbus_reg_addr` int(11) DEFAULT NULL COMMENT 'modebus寄存器地址', `modbus_data_type` int(11) DEFAULT NULL COMMENT 'modbus在寄存器中的实际数据类型', `opcua_data_con` mediumtext COMMENT 'opcua特殊数据', `type` char(10) DEFAULT 'variable' COMMENT '类型(variable:变量,rule:规则)', `unique_code` varchar(50) NOT NULL COMMENT '网关编号', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2452557 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='接口变量表'; "image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20240919/efc6db6479b42d768c5d721df073177e.png)