首页 > 数据库 >从海量数据表中筛选符合不同条件组合的数据的SQL优化

从海量数据表中筛选符合不同条件组合的数据的SQL优化

时间:2024-04-27 10:55:56浏览次数:16  
标签:f1 f2 海量 SQL 数据表 sn tab wip id

速度很慢的SQL脚本
 SET NOCOUNT ON;
 DECLARE @sn VARCHAR(200);
 DECLARE @n INT;
 DECLARE @sn_tab TABLE(id BIGINT,sn VARCHAR(200));

 IF OBJECT_ID('tempdb..#tab_f1') IS NOT NULL DROP TABLE #tab_f1
 CREATE TABLE #tab_f1(id BIGINT)
 CREATE INDEX idx_f1_id ON #tab_f1(id)

IF OBJECT_ID('tempdb..#tab_f2') IS NOT NULL DROP TABLE #tab_f2
 CREATE TABLE #tab_f2(id BIGINT)
 CREATE INDEX idx_f2_id ON #tab_f2(id)

 WHILE EXISTS(SELECT 1 FROM HMFG.dbo.t_sn_wip_240426 WHERE opstatus=0)
 BEGIN 
	
	DELETE FROM @sn_tab;
	INSERT INTO @sn_tab(id,sn)
	SELECT TOP 1000  snwp_id,snwp_serial_number FROM HMFG.dbo.t_sn_wip_240426 WHERE opstatus=0;

	INSERT INTO #tab_f1(id)
	SELECT stb.id FROM @sn_tab  stb WHERE EXISTS(SELECT 1 FROM HTPV.dbo.t_program_values_temp0426 tpv
	WHERE tpv.pgvl_serial_number=stb.sn
	AND tpv.pgvl_step_name = 'Efficiency & Power Factor Test 230V 5V PIN' AND tpv.pgvl_item_name = 'Output 1 Pin' AND  tpv.pgvl_item_para = 'Vin=230.000 Fin=50.000,A/O/V=0.000' AND	 tpv.pgvl_values = '0')

	INSERT INTO #tab_f2(id)
	SELECT stb.id FROM @sn_tab  stb WHERE EXISTS(SELECT 1 FROM HTPV.dbo.t_program_values_temp0426 tpv
	WHERE tpv.pgvl_serial_number=stb.sn
	AND tpv.pgvl_step_name = '静态测试' AND tpv.pgvl_item_name = '输入功率(W)' AND  tpv.pgvl_item_para = 'Vin:230.0000,Fin:50.0000;LD NoLoad' AND tpv.pgvl_values = '0')

	IF EXISTS(SELECT 1 FROM #tab_f1)
	BEGIN
	    UPDATE HMFG.dbo.t_sn_wip_240426
		SET f1=1
		FROM HMFG.dbo.t_sn_wip_240426 wip INNER JOIN #tab_f1 f1 ON wip.snwp_id=f1.id;
	END

	IF EXISTS(SELECT 1 FROM #tab_f2)
	BEGIN
	    UPDATE HMFG.dbo.t_sn_wip_240426
		SET f2=1
		FROM HMFG.dbo.t_sn_wip_240426 wip INNER JOIN #tab_f2 f2 ON wip.snwp_id=f2.id;
	END

	UPDATE HMFG.dbo.t_sn_wip_240426 SET opstatus=1 
	FROM  HMFG.dbo.t_sn_wip_240426 wip
	INNER JOIN @sn_tab st ON wip.snwp_id=st.id
	SET  @n= @@ROWCOUNT;

	PRINT @n;
 END

脚本主要存在以下问题:

  1. 循环处理:脚本使用了一个WHILE循环,循环直到处理完HMFG.dbo.t_sn_wip_240426表中所有opstatus=0的行。这种迭代方式可能会非常消耗资源,尤其是当这类行数众多时。循环处理会导致数据库引擎反复执行相同的查询逻辑,增加了数据库服务器的负担,且不利于充分利用数据库的批量处理能力。

  2. 重复查询与子查询:在每次循环中,脚本都会从HMFG.dbo.t_sn_wip_240426表中选取前1000个待处理的snwp_id和snwp_serial_number,然后分别对这些记录进行两次EXISTS子查询,以确定是否满足设置f1和f2标志的条件。这种做法不仅重复查询了HTPV.dbo.t_program_values_temp0426表,而且在数据量较大时,子查询可能会成为性能瓶颈。

  3. 临时表与索引:虽然您为临时表#tab_f1和#tab_f2创建了索引,但每次循环都要清空并重新插入数据,导致临时表的使用效率不高。同时,临时表的插入操作本身也增加了额外的写入开销。

  4. 多次更新:脚本通过两次UPDATE语句分别设置f1和f2标志,然后再进行一次UPDATE操作来设置opstatus。多次更新操作不仅增加了数据库事务的复杂性,还可能导致更多的锁竞争和资源消耗。


优化后代码
SET NOCOUNT ON;

IF OBJECT_ID('tempdb..#tab_f1') IS NOT NULL DROP TABLE #tab_f1;
IF OBJECT_ID('tempdb..#tab_f2') IS NOT NULL DROP TABLE #tab_f2;

CREATE TABLE #tab_f1 (
    snwp_id BIGINT PRIMARY KEY,
    f1 BIT NOT NULL DEFAULT (0)
);

CREATE TABLE #tab_f2 (
    snwp_id BIGINT PRIMARY KEY,
    f2 BIT NOT NULL DEFAULT (0)
);

-- 预计算条件组合对应的t_sn_wip_240426.snwp_id集合
WITH cte_condition_combinations AS (
    SELECT DISTINCT
        tpv.pgvl_serial_number,
        CASE WHEN tpv.pgvl_step_name = 'Efficiency & Power Factor Test 230V 5V PIN'
             AND tpv.pgvl_item_name = 'Output 1 Pin'
             AND tpv.pgvl_item_para = 'Vin=230.000 Fin=50.000,A/O/V=0.000'
             AND tpv.pgvl_values = '0' THEN 1 ELSE 0 END AS f1_condition_met,
        CASE WHEN tpv.pgvl_step_name = '静态测试'
             AND tpv.pgvl_item_name = '输入功率(W)'
             AND tpv.pgvl_item_para = 'Vin:230.0000,Fin:50.0000;LD NoLoad'
             AND tpv.pgvl_values = '0' THEN 1 ELSE 0 END AS f2_condition_met
    FROM HTPV.dbo.t_program_values_temp0426 tpv
)
-- 更新#tab_f1和#tab_f2,记录满足条件的snwp_id及其对应的f1/f2标志
INSERT INTO #tab_f1 (snwp_id, f1)
SELECT wip.snwp_id, MAX(f1_condition_met) AS f1
FROM HMFG.dbo.t_sn_wip_240426 wip
INNER JOIN cte_condition_combinations cc ON wip.snwp_serial_number = cc.pgvl_serial_number
WHERE wip.opstatus = 0
GROUP BY wip.snwp_id;

INSERT INTO #tab_f2 (snwp_id, f2)
SELECT wip.snwp_id, MAX(f2_condition_met) AS f2
FROM HMFG.dbo.t_sn_wip_240426 wip
INNER JOIN cte_condition_combinations cc ON wip.snwp_serial_number = cc.pgvl_serial_number
WHERE wip.opstatus = 0
GROUP BY wip.snwp_id;

-- 一次性更新HMFG.dbo.t_sn_wip_240426表
UPDATE HMFG.dbo.t_sn_wip_240426
SET f1 = t1.f1,
    f2 = t2.f2,
    opstatus = 1
FROM HMFG.dbo.t_sn_wip_240426 wip
LEFT JOIN #tab_f1 t1 ON wip.snwp_id = t1.snwp_id
LEFT JOIN #tab_f2 t2 ON wip.snwp_id = t2.snwp_id
WHERE wip.opstatus = 0;

-- 输出更新的行数
DECLARE @n INT = @@ROWCOUNT;
PRINT @n;

主要优化措施如下:

  1. 避免循环:原脚本使用WHILE循环逐批处理数据,这里改为一次性处理所有符合条件的数据。

  2. 预计算:通过CTE(公用表表达式)预先计算出HTPV.dbo.t_program_values_temp0426表中每个条件组合对应的HMFG.dbo.t_sn_wip_240426.snwp_id集合,减少后续查询的复杂度。

  3. 合并更新:将原脚本中分别更新f1和f2的两步操作合并为一次UPDATE语句,同时更新f1、f2和opstatus字段。

  4. 简化临时表:修改临时表#tab_f1和#tab_f2的结构,直接存储满足条件的snwp_id及其对应的f1和f2标志,省去了多次EXISTS子查询。

  5. 使用LEFT JOIN:在最终的UPDATE语句中,使用LEFT JOIN确保即使某些snwp_id在临时表中不存在(即不满足条件),也能正确更新其opstatus字段为1。

标签:f1,f2,海量,SQL,数据表,sn,tab,wip,id
From: https://www.cnblogs.com/voyager-rz/p/18161816

相关文章

  • MySQL Group Replication
    MySQL组复制              在MySQL复制集的基础上,将服务器划分为逻辑组,每组一个复制集。单主模式可以说是主从复制集的替代品,在主从复制集的基础上提供了部分自动化功能,他可以提供:1.复制集启动时自动选主,不需要手动指定2.主......
  • 【专题】2024中国零售业发展报告-拥抱“性价比时代”报告合集PDF分享(附原数据表)
    原文链接:https://tecdat.cn/?p=36050原文出处:拓端数据部落公众号在消费升级与降级交织的复杂市场背景下,中国零售市场正迈向性价比主导新阶段,高价值追求成核心竞争力。国家统计局数据显示,一季度GDP和居民收入增长,但社零和零售增速放缓,消费信心待提振。2023年快消品零售市场销售额......
  • mybatisplus乐观锁实现批量更新(在sql中实现)
    mybatisplus乐观锁实现批量更新在MyBatis-Plus中,乐观锁通常用于处理并发更新数据的问题。乐观锁实现批量更新时,可以使用版本号或者时间戳来保证数据的一致性。以下是使用乐观锁实现批量更新的示例代码:首先,在你的实体类中添加版本号字段:importcom.baomidou.mybatis......
  • SQL窗口分析函数使用详解系列三之偏移量类窗口函数
    1.综述本文以HiveSQL语法进行代码演示。对于其他数据库来说同样也适用,比如SparkSQL,FlinkSQL以及Mysql8,Oracle,SqlServer等传统的关系型数据库。已更新第一类聚合函数类,点击这里阅读①SQL窗口函数系列一之聚合函数类②SQL窗口函数系列二之分组排序窗口函数本节介绍Hive窗口分......
  • 利用python将沪深300股票历史数据存储在sqlite3
    一、环境准备1、python3中自带了sqlite3参考https://www.runoob.com/sqlite/sqlite-tutorial.html2、在sqlite中建表CREATETABLE[stock]([id]NVARCHAR(48),[name]NVARCHAR(24), [code]NVARCHAR(24),[date]INTEGERNOTNULL,[open]REAL,[close]......
  • postgresql中视图建立,字段拼接,同一个表的多行之间的多个字段相减
    首先表是这样的CREATETABLEpublic.tb_realtime_data( s_idvarchar(48)NOTNULL, sensor_namevarchar(48)NULL, sensor_index_codevarchar(48)NULL, sensor_valuenumeric(20,10)NULL, statistics_statusint4NULL, alarm_timetimestampNOTNULL, create_time......
  • postgresql 多条记录合并一条,或取最新的一条数据
    将一个表中的某一列的多行数据拼接成一行一种方法SELECTperson_idASjob_no,string_agg(person_name,',')asstr_person_nameFROMpublic.tb_attendance_modelWHEREcreate_time>='2019-06-1700:00:00.000000'ANDcreate_time<'2020-0......
  • SQLAlchemy中filter()和filter_by()有什么区别
    1.filter用类名.属性名,比较用==,filter_by直接用属性名,比较用=2.filter不支持组合查询,只能连续调用filter来变相实现。session.query(Dashboard).filter(Dashboard.id.in_(dashboard_ids_int)) .all()dashboard=(db.session.query(Dashboard).filter_by(id=dashboard_......
  • mysql 数据库时区问题
    当数据库时区设置为国际时区时jdbc-url中添加以下配置serverTimezone=GMT%2B0Java服务中设置东八区TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));使用mybatis红的mapper.xml<resultMapid="BaseResultMap"type="cn.xs.qxj.mtk.pojo.XpCallInfo"......
  • sql语句优化的30种方法
    作者:羋虹光链接:https://www.jianshu.com/p/3ab117c83d0b1.对查询进行优化,应尽量避免全表扫描,首先应考虑在where及orderby涉及的列上建立索引。2.应尽量避免在where子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。3.应尽量避免在where子句中对字段进......