前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一个简单的sql审核案例 (r8笔记第90天)

一个简单的sql审核案例 (r8笔记第90天)

作者头像
jeanron100
发布2018-03-19 16:03:15
6760
发布2018-03-19 16:03:15
举报

今天开发的同学发来一封邮件,希望我帮忙对一个sql语句做一个评估。他们也着急要用,但是为了稳妥起见,还是希望我来审核一下,这是一个好的习惯。 打开邮件,看到的语句是下面这样的形式。 select a.cout1+b.cout2 from (select count(*) as cout1 from TEST_ONLINE where CN='' and to_char(LOGIN_TIME,'yyyymmdd') = to_char(sysdate,'yyyymmdd') and rownum = 1) a,(select count(*) as cout2 from TEST_USER_CENTER where CN='' and to_char(LAST_LOGOUT,'yyyymmdd') = to_char(sysdate,'yyyymmdd') and rownum = 1) b; 看到这个语句,确实需要审核。 首先从sql语句结构上来说,实在不够好。 如果两个子查询的结果集条数大于1,很可能走笛卡尔积,貌似开发的同学也注意到了这一点,在两个子查询的末尾都加了rownum=1的字样,这样就肯定能够保证语句能够始终有1条以内的记录显示。所以这个语句看起来可以调整的空间不大。 但是我们做sql审核,也离不开表的属性信息。这两个表是OLTP的数据表,里面会有大量的实时数据变化,看看两个子查询中的过滤条件,是根据日期来作为 单位统计的,而一个核心字段就是CN了。看到这种情况,如果每日存在大量的数据,使用to_char(LAST_LOGOUT,'yyyymmdd')这 种方式肯定是有弊端,但是看需求是想精确到日为单位的数据,那么在这种情况下的关键就是CN了。 带着疑问继续查看,发现CN在两个表中都是主键,那么这种情况就好办多了。对于日期带来的困扰,其实影响不大,而且根据数据的分布,一个CN对应的数据是 唯一性的,那么使用rownum=1就有些多余了,然后再来看日期的过滤,有了CN的唯一性约束过滤,数据要么有匹配的是1条,要么就是没有匹配的0条。 结果也是显而易见,明白了这一点,这个时候看起来思路就清晰多了,这个查询的结果应该是在0~2之间。 对于这个语句有了更深入一步的认识,我们就来简单的改造一下。 这样的形式: select a.cout1+b.cout2 from (select count(*) as cout1 from TEST_ONLINE where CN='xxx' and to_char(LOGIN_TIME,'yyyymmdd') = to_char(sysdate,'yyyymmdd')) a,(select count(*) as cout2 from TEST_USER_CENTER where CN='xxx' and to_char(LAST_LOGOUT,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) b; 或者: select (select count(*) as cout1 from TEST_ONLINE where CN='xxx' and to_char(LOGIN_TIME,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) +(select count(*) as cout2 from TEST_USER_CENTER where CN='xxx' and to_char(LAST_LOGOUT,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) from dual; 或者使用with with a as (select count(*) as cout1 from TEST_ONLINE where CN='xxx' and to_char(LOGIN_TIME,'yyyymmdd') = to_char(sysdate,'yyyymmdd') and ), b as (select count(*) as cout2 from TEST_USER_CENTER where CN='xxx' and to_char(LAST_LOGOUT,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) select a.count1+b.count2 from a,b; 在目前满足条件的情况下,性能差别应该不大。如果CN为非唯一性约束,这个问题还是需要好好斟酌一下了,如果在 LOGIN_TIME,LOGOUT_TIME上有索引还是需要避免使用日期的二次格式化,而且在这个基础上,我应该在末尾使用group by而不是rownum=1了。 这样语句可能就变成了下面的形式。 select a.cout1+b.cout2 from (select count(*) as cout1 from TEST_ONLINE where CN='xxx' and LOGIN_TIME between trunc(sysdate) and to_date(sysdate,'yyyy-mm-dd hh24:mi:ss') group by LOGIN_TIME) a,(select count(*) as cout2 from TEST_USER_CENTER where CN='xxx' and LOGOUT_TIME between trunc(sysdate) and to_date(sysdate,'yyyy-mm-dd hh24:mi:ss') group by LOGOUT_TIME) b; 还有其它更多的改进方法,暂且讨论到这里。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 杨建荣的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档