从一段代码重构谈谈数据库应用中通过java运算减少sql的重要性

本文通过对比分析,展示了如何通过减少SQL查询次数并利用编程语言进行数据处理,从而显著提高系统的运行效率。具体案例中,通过将多次SQL查询整合为一次,并在Java中进行后续处理,实现了代码的简化和性能的大幅提升。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文旨在讨论数据库应用中通过编程语言(Java、Python等)替代SQL的重要性,即SQL只负责简单的增、删、改、查操作,业务逻辑运算都由编程语言实现。我们通过一个在Code Review时碰到的真实场景谈谈编程语言和SQL各司其职的重要性。

1、修改前的代码片段
	@SuppressWarnings("unchecked")
	public Map<String, Double> getAvlMoney(Map<String, Object> para) {
		DataAdapter adapter = new DataAdapter();
		Map<String, Double> moneyMap = this.getClientMoney(para);
		
		String sql = "select sum(money_with_tax) goods_money from sale_so_bill "
				+ "where co_id = #co_id# and customer_id = #client_id# "
				+ "and bill_status = '录入' and bill_type = '报损'";
		Double baosun = TypeUtil.toDouble(adapter.getVar(sql, para), 0D);
		
		Double avlfunds = 0D;
		Double jiegai = 0D;
		Double mianpin = 0D;
		Double discount = 0D;
		sql = "select sum(money_with_tax) goods_money, sum(goods_discount) goods_discount, "
				+ "sum(goods_jiegai) goods_jg, sum(goods_mp) goods_mp "
				+ "from sale_so_bill "
				+ "where co_id = #co_id# and customer_id = #client_id# "
				+ "and bill_status = '录入' and bill_type = '标准'";
		Map<String, Object> m = adapter.queryForObject(sql, para);
		if (m != null) {
			avlfunds = TypeUtil.toDouble(m.get("goods_money"), 0D);
			jiegai = TypeUtil.toDouble(m.get("goods_jg"), 0D);
			mianpin = TypeUtil.toDouble(m.get("goods_mp"), 0D);
			discount = TypeUtil.toDouble(m.get("goods_discount"), 0D);
		}
		
		sql = "select sum(goods_discount) from sale_so_bill "
				+ "where co_id = #co_id# "
				+ "and customer_id = #client_id# and bill_status = '录入' and bill_type = '广宣品-客户'";
		discount += TypeUtil.toDouble(adapter.getVar(sql, para), 0D);
		
		//刨除指定订单金额.
		if (! TypeUtil.isEmpty(para.get("bill_id"))) {
			sql = "select bill_type, money_with_tax goods_money, goods_jiegai, goods_mp, goods_discount "
					+ "from sale_so_bill where co_id = #co_id# and sid = #bill_id#";
			m = adapter.queryForObject(sql, para);
			if (m != null) {
				if ("报损".equals(m.get("bill_type"))) {
					baosun = baosun - TypeUtil.toDouble(m.get("goods_money"), 0D);
				} else {
					avlfunds = avlfunds - TypeUtil.toDouble(m.get("goods_money"), 0D);
					jiegai = jiegai - TypeUtil.toDouble(m.get("goods_jiegai"), 0D);
					mianpin = mianpin - TypeUtil.toDouble(m.get("goods_mp"), 0D);
					discount = discount - TypeUtil.toDouble(m.get("goods_discount"), 0D);
				}
			}
		}
		
		moneyMap.put("avlfunds", TypeUtil.doubleRound(moneyMap.get("avlfunds") - avlfunds, 2));
		moneyMap.put("jiegai", TypeUtil.doubleRound(moneyMap.get("jiegai") - jiegai, 2));
		moneyMap.put("mianpin", TypeUtil.doubleRound(moneyMap.get("mianpin") - mianpin, 2));
		moneyMap.put("discount", TypeUtil.doubleRound(moneyMap.get("discount") - discount, 2));
		moneyMap.put("baosun", TypeUtil.doubleRound(moneyMap.get("baosun") - baosun, 2));
		
		return moneyMap;
	}

代码说明:
1)不要考虑返回值类型的合理性(比如是否用BigDecimal保存金额等),DataAdapter是如何进行数据查询的,我们重点关注其运算逻辑;
2)该代码返回客户可报站资金(真实资金,折扣资金discount,免品资金mianpin,报损资金baosun等)

可报站资金 = 客户资金余额 - 已报站但是未发货的占用资金
客户资金余额, 通过Map<String, Double> moneyMap = this.getClientMoney(para)获取
moneyMap 扣减 报损订单报损资金,1次sql执行
moneyMap 扣减 标准订单资金、奖盖、折扣、免品,1次sql执行
moneyMap 扣减 光宣判订单折扣资金,1次sql执行
moneyMap 排除指定订单,1次sql执行
得到客户资金余额后,计算可报站资金,总共又耗费4次sql执行

3)通过分析,我们可以看出,得到客户资金余额后,计算可报站资金,只要1次sql执行得到大集合,然后java操作大集合即可,代码修改如下。

2、修改后的代码
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public Map<String, Double> getAvlMoney(Map<String, Object> para) {
		DataAdapter adapter = new DataAdapter();
		Map<String, Double> moneyMap = this.getClientMoney(para);
		
		String sql = "select goods_money, goods_funds, goods_zk, goods_jg, goods_mp from sale_so_bill "
				+ "where co_id = #co_id# and client_id = #client_id# and status = '录入' "
				+ "<dynamic>"
				+	"<isNotEmpty property='bill_id' prepend='and'>sid != #bill_id#</isNotEmpty>"
				+ "</dynamic>";
		List<Map> list = adapter.queryForList(sql, para);
		if (list == null) {
			return moneyMap;
		}
		for (Map map : list) {
			if ("报损".equals(map.get("bill_type"))) {
				moneyMap.put("baosun", moneyMap.get("baosun") - TypeUtil.toDouble(map.get("baosun"), 0D));
			} else if ("标准".equals(map.get("bill_type"))) {
				moneyMap.put("avlfunds", moneyMap.get("avlfunds") - TypeUtil.toDouble(map.get("goods_funds"), 0D));
				moneyMap.put("jiegai", moneyMap.get("jiegai") - TypeUtil.toDouble(map.get("goods_jg"), 0D));
				moneyMap.put("discount", moneyMap.get("discount") - TypeUtil.toDouble(map.get("goods_zk"), 0D));
				moneyMap.put("mianpin", moneyMap.get("mianpin") - TypeUtil.toDouble(map.get("goods_mp"), 0D));
			} else if ("广宣品-客户".equals(map.get("bill_type"))) {
				moneyMap.put("discount", moneyMap.get("discount") - TypeUtil.toDouble(map.get("goods_money"), 0D));
			}
		}
		return moneyMap;
	}

代码说明:
1)执行1次sql将符合要求的订单全部找出来;
2)根据moneyMap和订单资金进行运算,返回结果;

3、比较

1)修改后的代码,简洁,结果更清晰;
2)性能好很多

由于一个客户有效未发货的订单通常不会超过3单,因此一个sql返回的大集合和修改前分别返回的数据集合,数量级相当;
由于数据集合少,java循环运算成本几乎可忽略不计;
sql执行次数只有修改前的1/4,性能几乎可以提升3倍。

4、实际应用场景

尽可能多的编程语言实现,尽可能少的sql实现,有几个实际应用场景:
1)尽可能少用存储过程;
2)多个小查询看能不能替换成一个大查询+编程语言加工实现;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值