赞
踩
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
DROP TABLE IF EXISTS `customer_wallet_detail`; CREATE TABLE `customer_wallet_detail` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `customer_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID', `happen_amount` varchar(15) NULL DEFAULT '0' COMMENT '发生金额 带-号的代表扣款', `balance_amount` varchar(15) NULL DEFAULT '0' COMMENT '可用余额', `create_time` bigint(20) NULL DEFAULT NULL COMMENT '发生时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB COMMENT = '用户钱包明细'; INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (1, 1, '100', '100', 1670300656630); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (2, 1, '-10', '90', 1670300656640); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (3, 1, '5', '95', 1670300656650); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (4, 3, '998', '998', 1670300656660); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (5, 3, '-100', '898', 1670300656670); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (6, 3, '-98', '800', 1670300656680); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (7, 2, '666', '666', 1670300656690); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (8, 2, '-66', '600', 1670300656695); INSERT INTO `customer_wallet_detail`(`id`, `customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (9, 2, '-600', '0', 1670300656699);
SELECT
*
FROM
( SELECT * FROM customer_wallet_detail ORDER BY create_time DESC ) t1
GROUP BY
t1.customer_id;
使用 DISTINCT 查询进行去重的主要原理是通过先对要进行去重的数据进行分组操作,然后从分组后的每组数据中去一条返回给客户端,MySQL语句优化器会认为子查询中进行的其它处理无法合并,查看执行计划和优化后的语句还是和原语句一致,会先执行子查询然后再执行分组查询。
PS:这里使用内连接查询而不使用 IN 查询是因为我测试时发现连接查询会比 IN 查询性能要高50%以上,这个和底层查询机制有关有兴趣可以查看 IN 查询和连接查询的执行计划。
1、准备100w测试数据
# 创建表 DROP TABLE IF EXISTS `customer_wallet_detail_test`; CREATE TABLE `customer_wallet_detail_test` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `customer_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID', `happen_amount` varchar(15) NULL DEFAULT '0' COMMENT '发生金额 带-号的代表扣款', `balance_amount` varchar(15) NULL DEFAULT '0' COMMENT '可用余额', `create_time` bigint(20) NULL DEFAULT NULL COMMENT '发生时间', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB COMMENT = '用户钱包明细'; ## 创建一个插入数据的存储过程 DROP PROCEDURE IF EXISTS insert_procedure; delimiter;; CREATE PROCEDURE insert_procedure () BEGIN # 定义循环值 DECLARE i INT DEFAULT 1; #定义一个错误的变量,类型是整形,默认是0 DECLARE t_error INTEGER DEFAULT 0; #捕获到sql的错误,就设置t_error为1 DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET t_error=1; # 开启事务 START TRANSACTION; # 开始循环插入 WHILE ( i <= 1000000 ) DO INSERT INTO `customer_wallet_detail_test`(`customer_id`, `happen_amount`, `balance_amount`, `create_time`) VALUES (CEIL(RAND() * 1000), CEIL(RAND() * 1000), CEIL(RAND() * 1000), UNIX_TIMESTAMP() * 1000); SET i = i + 1; END WHILE; #如果捕获到错误 IF t_error=1 THEN #回滚 ROLLBACK; ELSE #提交 COMMIT; END IF; END;; delimiter; # 调用存储过程插入数据 CALL insert_procedure ();
方法一查询耗时测试和优化
方法二查询耗时测试和优化
方法三查询耗时测试和优化
结合我的业务经过测试,目前看来方法三是最合适的,性能较高,方案一和方案二性能较差,最终选择那个方案主要看业务而定,而且这里查询都是没有where条件,在添加上where条件并且附加上辅助查询的索引后,查询耗时会有很大变化,结合业务选择一种方法即可。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。