关于重复性校验的一条 SQL 优化问题请教

2017-11-16 17:12:11 +08:00
 ZEOH

Oracle 数据库一张表有如下字段:
FOO
| 字段     | 类型      | 说明                 |
| LOCATION    | VARCHAR2(512) | 地点,可以为多个,格式如:北京|上海  |
| STARTTIME   | VARCHAR2(20) | 开始时间,格式为:YYYYMMDD24HHMISS |
| ENDTIME    | VARCHAR2(20) | 结束时间,格式为:YYYYMMDD24HHMISS |
| FILED_A     | VARCHAR2(30) | 字段 A,有可能为空           |
| FILED_B     | VARCHAR2(30) | 字段 B,有可能为空           |
| FILED_C     | VARCHAR2(30) | 字段 C,有可能为空           |
| FILED_D     | VARCHAR2(30) | 字段 D,有可能为空           |

需求是用文件导入的方式批量对这张表进行新增操作,但导入时需要对数据执行一系列校验。
其中有一个步骤是 重复性校验。若同时满足以下条件,则说明导入的数据已经存在,校验失败:

  1. FILED_A、FILED_B、FILED_C、FILED_D 四个字段完全相同;
  2. 导入数据的时间区间( STARTTIME ~ ENDTIME )与已经存在的数据时间有交叉(如数据 A [20171101 ~ 20171103]与数据 B [20171102 ~ 20171104] 视为交叉;
  3. 导入数据的 LOCATION 与已经存在的数据有交叉(如数据 A [北京|上海] 与数据 B[上海|杭州] 视为交叉)。

原先的方案是在内存中比较,但由于导入的数据往往较大,如果取一条数据查一次数据库看存不存在,5000 条数据就要查 5000 次,性能比较差。 于是考虑把待校验的数据放在一张临时表中,一次性对所有数据进行对比。

临时表与正式表结构基本一致,但多了下面一个字段:

TEMP_FOO
| 字段     | 类型     | 说明   |
| CHECKRESULT | VARCHAR2(20) | 校验结果 |

目前写出的重复性校验 SQL 如下(如果临时表 TEMP_FOO 待校验的数据已经存在正式表 FOO 中,则将其校验结果字段更新为 Repeat ):

UPDATE TEMP_FOO t
SET t.CHECKRESULT = 'Repeat'
WHERE EXISTS (
    SELECT 1 FROM FOO o
    WHERE regexp_like(o.LOCATION, t.LOCATION)
    AND o.STARTTIME >= concat(to_char(to_date(t.STARTTIME,'yyyymmddhh24miss'),'yyyymmdd'),'000000')
    AND o.STARTTIME < concat(to_char(to_date(t.STARTTIME,'yyyymmddhh24miss')+1,'yyyymmdd'),'000000')
    AND o.ENDTIME >= concat(to_char(to_date(t.ENDTIME,'yyyymmddhh24miss'),'yyyymmdd'),'000000')
    AND o.ENDTIME < concat(to_char(to_date(t.ENDTIME,'yyyymmddhh24miss')+1,'yyyymmdd'),'000000')
    AND nvl(t.FILED_A, '0') = nvl(o.FILED_A, '0')
    AND nvl(t.FILED_B, '0') = nvl(o.FILED_B, '0')
    AND nvl(t.FILED_C, '0') = nvl(o.FILED_C, '0')
    AND nvl(t.FILED_D, '0') = nvl(o.FILED_D, '0')
    )

现在有几个问题想请教大家:

  1. 当导入数据量很大(超过 5000 条),该条 SQL 执行效率仍然很低,请问是否有办法优化?
  2. 有时候 WHERE 子句中,FILED_A、FILED_B、FILED_C、FILED_D 四个条件已经能够保证查询结果为 0 了,为什么 oracle 还是缓慢地执行了全部筛选条件?
  3. 不限于在数据库中做对比,是否还有其他方案可以高效地进行重复性校验?

有任何一点建议都可以提出,非常感谢!

1680 次点击
所在节点    问与答
5 条回复
canbingzt
2017-11-16 17:37:55 +08:00
感觉把校验内容单独建表是不是效率更高
1.建一张时间表,保存已有的时间,你的例子时间只到天,那么就把所有存在的天保存起来,不保存时间段
2.建一张地点表,保存已有的地点
picone
2017-11-16 19:11:11 +08:00
时间方面,字段类型改成是 TIMESTAMP 或 DATE。

如果要放在内存做验证也不是不可以,做一个链表存放时间返回,详细的可以参考操作系统的内存管理是怎么做的。
ZEOH
2017-11-17 09:26:06 +08:00
@canbingzt 不是很清楚您的意思,能否仔细说明下?
ZEOH
2017-11-17 09:26:34 +08:00
@picone 好的,我去看下
picone
2017-11-17 10:10:05 +08:00
@ZEOH #4 我说的是指时间校验那方面,可以参考一下内存管理, 他会标识哪一块已用,哪一块未用,合并连续块,用这种方法就不用很大的内存了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/406986

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX