一、select 1 from table;
與 select anycol(目的表集合中的任意一行)from table;
與 select * from table;
從作用上來說是沒有差別的,都是查看是否有記錄,一般是作條件查詢用的。select 1 from table中的1是一常量(可以為任意數值),查到的所有行的值都是它,但從效率上來說,1>anycol>*,因為不用查字典表。
注意:
當只關心數據表有多少記錄行而不需要知道具體的字段值時,類似“select 1 from table”是一個很不錯的SQL語句寫法,它通常用于子查詢。
這樣可以減少系統開銷,提高運行效率。因為這樣寫的SQL語句,數據庫引擎就不會去檢索數據表里每條具體的記錄和每條記錄里每個具體的字段值并將它們放到內存里,而是根據查詢到有多少記錄行存在就輸出多少個“1”,每個“1”代表有1行記錄,同時選用數字1還因為它所占用的內存空間最小,當然用數字0的效果也一樣。
測試:
-
select 1 from table
增加臨時列,每行的列值是寫在select后的數。這條sql語句中是1。 -
select count(1) from table
不管count(a) 的 a值如何變化,得出的值總是table表的行數。 -
select sum(1) from table
計算臨時列的和。
在Oracle中用 1 測試了一下,發現結果如下:
- 測試結果,得出一個行數和table表行數一樣的臨時列,每行的列值是1;
- 得出一個數,該數是table表的行數;
- 得出一個數,該數是table表的行數;
然后又用“2”測試,結果如下:
- 得出一個行數和table表行數一樣的臨時列,每行的列值是2;
- 得出一個數,該數是table表的行數;
- 得出一個數,該數是table表的行數×2的數。
再用不同的數測試:
- 得出一個行數和table表行數一樣的臨時列,每行的列值是寫在select后的數;
- 還是得出一個數,該數是table表的行數;
- 得出一個數,該數是table表的行數×寫在select后的數。
綜上所述:第一種的寫法是增加臨時列,每行的列值是寫在select后的數;第二種是不管count(a)的a值如何變化,得出的值總是table表的行數;第三種是計算臨時列的和。
二、count(列名) 、count(常量) 、count(*)
【強制】不要使用 count(列名) 或 count(常量) 來替代 count(*) , count(*) 是 SQL 92 定義的標準統計行數的語法,跟數據庫無關,跟 NULL 和非 NULL 無關。
說明:count(*) 會統計值為 NULL 的行,而 count(列名) 不會統計此列為 NULL 值的行。
【強制】 count(distinct col) 計算該列除 NULL 之外的不重復行數,注意 count(distinct col 1, col 2 ) 如果其中一列全為 NULL ,那么即使另一列有不同的值,也返回為 0。
【強制】當某一列的值全是 NULL 時, count(col) 的返回結果為 0,但 sum(col) 的返回結果為NULL ,因此使用 sum() 時需注意 NPE 問題。
正例:可以使用如下方式來避免 sum 的 NPE(NullPointerException) 問題:
select if ( isNull ( sum(g) ) ,0, sum(g) ) from table;
1??count(1) and count(*)
當表的數據量大些時,對表作分析之后,使用count(1)還要比使用count(*)用時多!
從執行計劃來看,count(1)和count(*)的效果是一樣的。但是在表做過分析之后,count(1)會比count(*)的用時少些(1w以內數據量),不過差不了多少。
如果count(1)是聚集索引時,那肯定是count(1)快,但是差的很小。
因為count(*),自動會優化指定到那一個字段。所以沒必要去count(1),用count(),sql會幫你完成優化的。因此:在有聚集索引時count(1)和count(*)基本沒有差別!
2??count(1) and count(字段)主要區別
- count(1) 會統計表中的所有的記錄數,包含字段為null 的記錄。
- count(字段) 會統計該字段在表中出現的次數,忽略字段為null 的情況。即不統計字段為null 的記錄。
3??count(*) 和 count(1)和count(列名)區別
執行效果上:
- count(*)包括了所有的列,相當于行數,在統計結果的時候,不會忽略列值為NULL
- count(1)包括了忽略所有列,用1代表代碼行,在統計結果的時候,不會忽略列值為NULL
- count(列名)只包括列名那一列,在統計結果的時候,會忽略列值為空(這里的空不是只空字符串或者0,而是表示null)的計數,即某個字段值為NULL時,不統計。
執行效率上:
- 列名為主鍵,count(列名)會比count(1)快
- 列名不為主鍵,count(1)會比count(列名)快
- 如果表多個列并且沒有主鍵,則 count(1)的執行效率優于 count(*)
- 如果有主鍵,則 select count(主鍵)的執行效率是最優的
如果表只有一個字段,則 select count(*) 最優。
4??實例分析
create table tab
(name char(1),
age char(2));
insert into tab values
('a', '14'),
('a', '15'),
('a', '15'),
('b', NULL),
('b', '16'),
('c', '17'),
('d', null),
('e', '');
select
name,count(name),count(1),count(*),count(age),count(distinct(age))
from tab
group by name;
三、SQL查找是否“存在”
根據條件從數據庫表中查詢『有』與『沒有』,只有兩種狀態。
1??常見寫法
業務代碼中,需要根據一個或多個條件,查詢是否存在記錄,不關心有多少條記錄。普遍的 SQL 寫法如下:
select count(*) from table where a = 1 AND b = 2;
業務代碼:
##### Java寫法:
int num = countDao.countDataByCondition(params);
if ( num > 0 ) {
//當存在時,執行這里的代碼
} else {
//當不存在時,執行這里的代碼
}
2??優化之后
select 1 from table where a = 1 AND b = 2 limit 1;
業務代碼:
##### Java寫法:
Integer exist = existDao.existDataByCondition(params);
if ( exist != NULL ) {
//當存在時,執行這里的代碼
} else {
//當不存在時,執行這里的代碼
}
sql 不再使用 count,而是改用 limit 1,讓數據庫查詢時遇到一條就返回,不要再繼續查找還有多少條。明知只有或者只要一條查詢結果,使用 “limit 1”,可以避免全表掃描,找到對應結果就不會再繼續掃描了。