【Oracle】亿级表下in查询替代方案
sinye56 2024-09-19 02:08 7 浏览 0 评论
文中使用的Oracle版本为10g。
在真实的业务场景中往往很难避免有“in”条件查询的时候,但我们都知道用“in”做条件查询时SQL是一般不会走索引(某些新版数据库除外),那如果“in”含大量条件甚至超过1000条该怎么办呢(大部分数据库在基于性能方面考虑限制了“in”条件不能超过1000个)?下面将结合一个例子,给各位详述我的解决方案。
后台输出截获的SQL脚本如下(因可能涉及敏感信息,为此将部分字段表述进行转换):
SELECT *
FROM (SELECT SHOWDATA.*, ROWNUM RN
FROM (SELECT DISTINCT A.OWNER_PHONE,
GP.NAME,
A.CALLTYPE AS CALLEDTYPE,
A.TRANS_PHONE,
A.TRANS_NAME NAMES,
A.TRANS_CALLED_INFO,
TO_CHAR(A.TRANS_STARTTIME,'yyyy-mm-dd HH24:mi:ss') AS TRANS_STARTTIME,
TO_CHAR(A.TRANS_STARTTIME, 'HH24') TRANS_HH,
A.TRANS_DURATION,
A.AR,
A.LAC,
A.CS,
A.LN,
A.CB,
A.CL,
A.CC,
A.CA,
A.OI,
A.CI,
A.TL,
A.TLA,
A.TCL,
A.TCLA,
A.TA,
A.ISR,
A.ISO
FROM GPB A
INNER JOIN GPBI GP ON A.PBII = GP.ID
WHERE A.IS = 0
AND A.TRANS_STARTTIME BETWEEN
TO_DATE('2015-09-09 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND
TO_DATE('2016-09-09 00:00:59', 'YYYY-MM-DD HH24:MI:SS')
AND A.OWNER_PHONE IN (15000000000, 15100000000, 15200000000, ...)
ORDER BY TRANS_STARTTIME DESC nulls last)
SHOWDATA)
WHERE RN > 0 AND RN <= 100
以上SQL有好几处地方可以优化但性能瓶颈在于“in”查询。以上看到的脚本内容是经过性能排查后截录的脚本片段,真实的脚本足够翻好几页(真想不明白之前写这个脚本的人是怎么想的)。
言归正传,这语句给我感觉:
1) 查询条件受到限制,最多只能查询1000个手机号码;
2) 由于使用“in”查询,这里OWNER_PHONE字段不能使用索引;
3) ORDER BY在完成“in”操作后还需进行一次全表扫描排序,这个也是另一个性能消耗点;
4) 最讽刺的是GPB 和 GPBI两个表前者是亿级表,后者是万级表,在INNER JOIN后最终只需要展示前100条数据,这前面大量运算有点浪费;
既然这样先将“in”查询问题先解决,这里我分成3步:
1. 建立一个TYPES(tabletype)
这个TYPE是一个TABLE类型的,代码如下:
CREATE OR REPLACE TYPE TABLETYPE AS TABLE OF VARCHAR2(32676);
2. 建立自定义函数STRSPLIT以PIPE ROW返回
不说废话,上代码:
CREATE OR REPLACE FUNCTION STRSPLIT (p_list CLOB, p_sep VARCHAR2 := ',')
RETURN tabletype
PIPELINED
IS
l_idx PLS_INTEGER;
v_list VARCHAR2 (32676) := trim(replace(p_list,chr(10),''));
BEGIN
LOOP
l_idx := INSTR (v_list, p_sep);
IF l_idx > 0
THEN
PIPE ROW (SUBSTR (v_list, 1, l_idx - 1));
v_list := SUBSTR (v_list, l_idx + LENGTH (p_sep));
ELSE
PIPE ROW (v_list);
EXIT;
END IF;
END LOOP;
END;
这个关于Oracle的字符串分割函数网上一搜一大把,各位酌情参考就可以了。函数生成后通过:
SELECT * FROM TABLE(STRSPLIT(‘A,B,C,D,E’));
得到一个虚拟的表。
3. 改造原SQL脚本
SELECT *
FROM (SELECT SHOWDATA.*, ROWNUM RN
FROM (SELECT DISTINCT A.OWNER_PHONE,
GP.NAME,
A.CALLTYPE AS CALLEDTYPE,
A.TRANS_PHONE,
A.TRANS_NAME NAMES,
A.TRANS_CALLED_INFO,
TO_CHAR(A.TRANS_STARTTIME,'yyyy-mm-dd HH24:mi:ss') AS TRANS_STARTTIME,
TO_CHAR(A.TRANS_STARTTIME, 'HH24') TRANS_HH,
A.TRANS_DURATION,
A.AR,
A.LAC,
A.CS,
A.LN,
A.CB,
A.CL,
A.CC,
A.CA,
A.OI,
A.CI,
A.TL,
A.TLA,
A.TCL,
A.TCLA,
A.TA,
A.ISR,
A.ISO
FROM GPB A
INNER JOIN GPBI GP ON A.PBII = GP.ID
INNER JOIN (
SELECT INN.COLUMN_VALUE AS IN_DATA
FROM (SELECT '' AS COLUMN_VALUE FROM DUAL WHERE 1 > 2
UNION ALL
SELECT * FROM TABLE(STRSPLIT('15000000000,15100000000,...'))
UNION ALL
SELECT * FROM TABLE(STRSPLIT('15200000000,15300000000,...'))
UNION ALL
......
) INN
) B ON A.OWNER_PHONE = B.IN_DATA
WHERE A.IS = 0
AND A.TRANS_STARTTIME BETWEEN
TO_DATE('2015-09-09 00:00:00', 'YYYY-MM-DD HH24:MI:SS') AND
TO_DATE('2016-09-09 00:00:59', 'YYYY-MM-DD HH24:MI:SS')
AND A.OWNER_PHONE IN (15000000000, 15100000000, 15200000000, ...)
ORDER BY TRANS_STARTTIME DESC nulls last)
SHOWDATA)
WHERE RN > 0 AND RN <= 100
这里用虚拟表进行内连接可以代替“in”操作,SELECT … UNION ALL 这部分内容通过MyBatis进行循环拼接也是可以实现的。由于不想在字符串末尾再删除UNION ALL字符,因此在查询开头加上一个查询DUAL表的操作并判断1>2即可。
动态条件内容将在Java内进行原数据的重组。Oracle自定义函数中参数内容不能太长(函数字段有长度限制),因此在Java中进行字符串长度限制分割,分割内容将保存到集合(List)中,通过参数传入DAO并在MyBatis中进行循环二次拼接。
这种方法无论需要“in”条件是多少,即使个数超过1000的情况下也是可以查询的,同时OWNER_PHONE字段可走索引。
具体查询性能对比如下:
改造前
改造后
同样是查询前100条数据,前者是16.475秒,而后者是1.841秒,可以看出查询速度的差异。
最后附上Java和MyBatis的代码,如下图:
这根据长度切割数据集的代码虽然不影响使用但有待改进ε=(′ο`*)))唉。
至于MyBatis就还是那样了。
相关推荐
- 6个接私活的网站,你有技术就有钱
-
如果觉得有帮助,还请大家帮忙多多转发,点个关注作者:发哥链接:GitHubDaily本篇文章会向大家推荐国内外几个接外包比较靠谱的平台,主旨是贵精不贵多。因此,像「猪x戒」这种会让程序员自贬身价,扰乱...
- Java开源可商用的CMS建站系统_java建站源码
-
Java研发的CMS内容管理系统具有许多优势和特点,包括以下几个方面:跨平台性:Java是一种跨平台的编程语言,可以在不同的操作系统上运行,包括Windows、Linux、Mac等。这意味着Java...
- SEO新手建站必看"干货"优质空间和功能选择技巧!
-
一.空间的分类服务器:远程的高级大型计算机。vps:虚拟服务器。虚拟空间:也称虚拟主机云主机:是在一组集群主机上虚拟出多个类似独立主机的部分,集群中每个主机上都有云主机的一个镜像,从而大大提高了虚拟主...
- 千字长文教你使用 宝塔面板 快速搭建网站
-
本文将教大家使用宝塔面板快速搭建网站,云服务器购买以及域名注册部分请自行上网搜索了解,亦可留言联系小编进行咨询。如果是和下方一样本地搭建演示的话,则不需要付费购买域名和主机。宝塔面板的是...
- BlueHost香港虚拟主机建站的5个优点
-
应该是从2006年左右开始,如果我们建站选择国内的主机需要备案手续,而且比较繁琐,且根据各地的不同政策还需要到接入点拍照登记个人信息等,一来比较繁琐,二来我们担心万一网站可能存在的信息问题导致不必要的...
- 10款好用的Linux服务器网站管理面板推荐
-
如今在建站时,很多人都会使用管理面板来辅助建站,因为相对于手动安装软件,面板更加简单而且高效,即使新手也能很快学会搭建网站,在本文中我们来推荐几款好用的网站管理面板宝塔面板宝塔面板是一款简单好用的网站...
- 小白拥有一台云服务器到底能干些什么?成就感爆棚的简单方案!
-
?云服务器是什么?云服务器(比如阿里云、腾讯云等)是提供给用户的一种虚拟服务器资源,你可以把它看作一台“rent的电脑”,只需要支付少量费用就可以拥有一个功能强大的网络设备。对于小白来说,拥有一...
- 苹果CMS,苹果CMS采集插件,苹果CMS快速建站(图文教程)
-
苹果CMS,有着强大的管理功能,管理后台界面大方、操作简单、功能齐全、模块众多、双端管理。苹果CMS加上丰富的系统标签,系统内置了丰富的cms标签并支持thinkphp框架标签完美融合,可以调取系统内...
- 新手搭建网站、小程序、APP等系统,如何选择服务器?
-
今天和小蔡和大家说说,新手搭建网站,如何选择服务器?废话不多说,直接来干货。服务器是存放网站源代码的容器,也是运行网站程序的工具,所以是不可或缺的。新手刚接触搭建网站,若不知道怎么去选择一台适合自己...
- 在海外VPS服务器(Hostinger)上配置宝塔面板的操作步骤
-
不得不说,宝塔面板是真的好用啊~用上就放不下了,一些海外的免费开源的服务器集成面板(比如CloudPanel)我也用了,不喜欢,真的不如宝塔面板方便耐用。今天聊一下在海外服务器(也包括国内服务器,没有...
- 干货盘点:每个wordpress站长都推荐完成的60个任务清单
-
构建和运营wordpress网站包含了很多重要任务,遗漏哪一方面都可能造成或大或小的不良后果,因此我们特别整理了这个任务清单,为你查漏补缺,希望能对您现在运营或者即将开始构建的wordpress网站有...
- 为什么站长喜欢选择BlueHost主机建站
-
BlueHost正式成立于2003年,从事主机(虚拟主机)业务至今已经将近十余年,无论从口碑还是用户的评价,我们基本很少看到关于Bluehost主机产品和商家负面的评论信息。从2014年开始,Blue...
- 自助建站时代来临 半小时成建站达人
-
“H5”意为第五代HTML,即第五代网页编写语言。自从1991年第一代HTML开始研发以来,网页编写、网站建设一直都属于高端技术行业,网站建设人员都是一些专业型人才,这也意味着网站的建设和维护都需要不...
- 现代化、开源的 Linux 服务器运维管理面板
-
1Panel是一个现代化、开源的Linux服务器运维管理面板。1Panel的功能和优势包括:快速建站:深度集成Wordpress和Halo,域名绑定、SSL证书配置等一键搞定;高效管理...
- [1Panel]开源,现代化,新一代的 Linux 服务器运维管理面板
-
测评介绍本期测评试用一下1Panel这款面板。1Panel是国内飞致云旗下开源产品。整个界面简洁清爽,后端使用GO开发,前端使用VUE的Element-Plus作为UI框架,整个面板的管理都是基于do...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle忘记用户名密码 (59)
- oracle11gr2安装教程 (55)
- mybatis调用oracle存储过程 (67)
- oracle spool的用法 (57)
- oracle asm 磁盘管理 (67)
- 前端 设计模式 (64)
- 前端面试vue (56)
- linux格式化 (55)
- linux图形界面 (62)
- linux文件压缩 (75)
- Linux设置权限 (53)
- linux服务器配置 (62)
- mysql安装linux (71)
- linux启动命令 (59)
- 查看linux磁盘 (72)
- linux用户组 (74)
- linux多线程 (70)
- linux设备驱动 (53)
- linux自启动 (59)
- linux网络命令 (55)
- linux传文件 (60)
- linux打包文件 (58)
- linux查看数据库 (61)
- linux获取ip (64)
- linux进程通信 (63)