乙個簡單的sql審核案例

2021-09-22 19:23:00 字數 2406 閱讀 2142

今天開發的同學發來一封郵件,希望我幫忙對乙個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了。

結果也是顯而易見,明白了這一點,這個時候看起來思路就清晰多了,這個查詢的結果應該是在0~2之間。

對於這個語句有了更深入一步的認識,我們就來簡單的改造一下。

這樣的形式:

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')) a,(select count(*) as cout2 from test_user_center where cn='***' and to_char(last_logout,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) b;

或者:select  (select count(*) as cout1 from test_online where cn='***' and to_char(login_time,'yyyymmdd') = to_char(sysdate,'yyyymmdd') ) +(select count(*) as cout2 from test_user_center where cn='***' 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='***' and to_char(login_time,'yyyymmdd') = to_char(sysdate,'yyyymmdd') and ),

b as (select count(*) as cout2 from test_user_center where cn='***' 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='***' 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='***' and logout_time between trunc(sysdate) and to_date(sysdate,'yyyy-mm-dd hh24:mi:ss')

group by logout_time) b;

還有其它更多的改進方法,暫且討論到這裡。

乙個簡單的sql

declare wokno varchar 500 用來記錄職工號 declare str nvarchar 4000 用來存放查詢語句 declare count int 求出總記錄數 declare i int set i 0 select count count distinct wokno ...

乙個案例的簡單總結

翻看去年處理的乙個案例,發現處理時間挺長的,而且這個案例也有點意思,就再看多兩眼,做個簡單總結。1.首先是應用伺服器效能不穩定,排查之後,伺服器是vm,要求加資源,並且所有資源都reserved.2.接著就是應用伺服器連線資料庫時很不穩定,資料庫經常報 recovery mode 好像是資料庫莫名被...

乙個簡單的乙個sql表遍歷

簡單的乙個sql表遍歷 一般我們寫儲存過程或者其他sql語句的時候都會用到迴圈遍歷資料,最常用的兩種就是 1 游標 2 臨時表 while 下面貼出示例 declare minrelogid int 這裡的 minrelogid 一般都是表中的主鍵 select top 1 minrelogid m...