COUNT(*)計算行數有哪些優化手段
COUNT(*)計算行數有哪些優化手段
--無索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
SET AUTOTRACE TRACEONLY
SET LINESIZE 1000
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--普通索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--唯一索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
UPDATE T_20170704_COUNT_LHR_01 T SET T.OBJECT_NAME=T.OBJECT_NAME||ROWNUM;
CREATE unique INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--常數索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(0);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--常數壓縮索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(0) COMPRESS;
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--點陣圖索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='lhr';
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='ldd' WHERE ROWNUM<=20000;
CREATE BITMAP INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
ALTER INDEX IDX_OBJECT_NAME PARALLEL 8;
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
-- 物化檢視
DROP MATERIALIZED VIEW MV_COUNT_T_LHR;
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='lhr';
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='ldd' WHERE ROWNUM<=20000;
CREATE MATERIALIZED VIEW MV_COUNT_T_LHR
BUILD IMMEDIATE
REFRESH ON COMMIT
ENABLE QUERY REWRITE
AS
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
SET AUTOTRACE TRACEONLY
SET LINESIZE 1000
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
--快取結果集
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
SET LINESIZE 1000
SET AUTOTRACE TRACEONLY
SELECT /*+ RESULT_CACHE */ COUNT(*) FROM T_20170704_COUNT_LHR_01;
--業務分析
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01 WHERE ROWNUM=1;
一、普通表(無索引)
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
COUNT(*)
----------
79300
LHR@orclasm > SET AUTOTRACE TRACEONLY
LHR@orclasm > SET LINESIZE 1000
LHR@orclasm > SET TIMING ON
LHR@orclasm > LHR@orclasm > LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 1395805058
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 317 (1)| 00:00:04 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| T_20170704_COUNT_LHR_01 | 91429 | 317 (1)| 00:00:04 |
--------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
1139 consistent gets
0 physical reads
0 redo size
527 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
二、普通索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.20
Execution Plan
----------------------------------------------------------
Plan hash value: 1178070731
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 114 (1)| 00:00:02 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_OBJECT_NAME | 91429 | 114 (1)| 00:00:02 |
---------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
400 consistent gets
0 physical reads
0 redo size
527 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
1、主鍵索引(唯一索引)
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE UNIQUE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
2、常數索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(0);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.01
Execution Plan
----------------------------------------------------------
Plan hash value: 1178070731
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 45 (3)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_OBJECT_NAME | 86597 | 45 (3)| 00:00:01 |
---------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
151 consistent gets
0 physical reads
0 redo size
528 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
3、常數壓縮索引
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
ALTER TABLE T_20170704_COUNT_LHR_01 MODIFY OBJECT_NAME NOT NULL;
CREATE INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(0) COMPRESS;
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
LHR@orclasm > LHR@orclasm > LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1178070731
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 38 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | INDEX FAST FULL SCAN| IDX_OBJECT_NAME | 86597 | 38 (0)| 00:00:01 |
---------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
129 consistent gets
0 physical reads
0 redo size
528 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
三、點陣圖索引
試驗如下:
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='lhr';
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='ldd' WHERE ROWNUM<=20000;
CREATE BITMAP INDEX IDX_OBJECT_NAME ON T_20170704_COUNT_LHR_01(OBJECT_NAME);
SET AUTOTRACE TRACEONLY
SET TIMING ON
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1696023018
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 5 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | BITMAP CONVERSION COUNT | | 91429 | 5 (0)| 00:00:01 |
| 3 | BITMAP INDEX FAST FULL SCAN| IDX_OBJECT_NAME | | | |
-----------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5 consistent gets
0 physical reads
0 redo size
527 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
1、點陣圖索引+並行
ALTER INDEX IDX_OBJECT_NAME PARALLEL 8;
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
並行技術可以加快執行速度,但一致性讀有所增加,但並行還是能加快整體執行速度。
四、物化檢視
這主要是應用在資料庫更新不是非常頻繁場景,用的是空間換時間。
DROP MATERIALIZED VIEW MV_COUNT_T_LHR;
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='lhr';
UPDATE T_20170704_COUNT_LHR_01 SET OBJECT_NAME='ldd' WHERE ROWNUM<=20000;
CREATE MATERIALIZED VIEW MV_COUNT_T_LHR
BUILD IMMEDIATE
REFRESH ON COMMIT
ENABLE QUERY REWRITE
AS
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
SET AUTOTRACE TRACEONLY
SET LINESIZE 1000
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
LHR@orclasm > SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.08
Execution Plan
----------------------------------------------------------
Plan hash value: 571421573
-----------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 13 | 3 (0)| 00:00:01 |
| 1 | MAT_VIEW REWRITE ACCESS FULL| MV_COUNT_T_LHR | 1 | 13 | 3 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
3 consistent gets
0 physical reads
0 redo size
531 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
五、快取結果
在Oracle 11g中提供了結果集快取特性。該快取是在共享記憶體中儲存全部的結果集。如果一個查詢SQL被執行,且它對應的結果集在快取中,那麼,該SQL的幾乎全部開銷都可以避免。
DROP TABLE T_20170704_COUNT_LHR_01 PURGE;
CREATE TABLE T_20170704_COUNT_LHR_01 AS SELECT * FROM DBA_OBJECTS;
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01;
SET LINESIZE 1000
SET AUTOTRACE TRACEONLY
SELECT /*+ RESULT_CACHE */ COUNT(*) FROM T_20170704_COUNT_LHR_01;
LHR@orclasm > LHR@orclasm > SELECT /*+ RESULT_CACHE */ COUNT(*) FROM T_20170704_COUNT_LHR_01;
Elapsed: 00:00:00.00
Execution Plan
----------------------------------------------------------
Plan hash value: 1395805058
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 317 (1)| 00:00:04 |
| 1 | RESULT CACHE | 6pp2f468gdjnj9v3s3mfwffd7t | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | TABLE ACCESS FULL| T_20170704_COUNT_LHR_01 | 86597 | 317 (1)| 00:00:04 |
------------------------------------------------------------------------------------------
Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=1; dependencies=(LHR.T_20170704_COUNT_LHR_01); attributes=(single-row); name="SELECT /*+ RESULT_CACHE */ COUNT(*) FROM T_20170704_COUNT_LHR_01"
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
528 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
六、根據業務規則判斷
若統計行數只是為了判斷表中是否有記錄,則可以使用ROWNUM=1,所以改寫後的SQL變為:
SELECT COUNT(*) FROM T_20170704_COUNT_LHR_01 WHERE ROWNUM=1;
該SQL無論表中資料多大,效能都不會太差。
七、分析需求
仔細分析需求後,可能會發現,統計行數這條SQL根本就是多餘的,那麼這條SQL語句就可以直接砍掉了。
八、總結
手段 |
命令 |
執行計劃 |
主要原理 |
詳細說明 |
效能情況 |
全表掃描 |
|
TABLE ACCESS FULL |
全表掃描 |
OLTP中,通常是最慢的方式。 |
邏輯讀為1139 |
增加普通索引 |
CREATE INDEX IDX_OBJECT_NAME ON T(OBJECT_NAME); |
INDEX FAST FULL SCAN |
從全表掃描轉成全索引掃描。 |
因為索引一般比表小的多,所以全表掃描轉成全索引掃描,效能能大幅度提升。 |
邏輯讀為400 |
常數索引 |
CREATE INDEX IDX_OBJECT_NAME ON T(0); |
INDEX FAST FULL SCAN |
從全表掃描轉成全索引掃描。 |
常數索引比普通索引更小。 |
邏輯讀為151 |
常數壓縮索引 |
CREATE INDEX IDX_OBJECT_NAME ON T(0) COMPRESS; |
INDEX FAST FULL SCAN |
從全表掃描轉成全索引掃描。 |
常數壓縮索引比常數索引更小。 |
邏輯讀為129 |
點陣圖索引 |
CREATE BITMAP INDEX IDX_OBJECT_NAME ON T(OBJECT_NAME); |
BITMAP INDEX FAST FULL SCAN |
從BTREE索引掃描轉成點陣圖索引掃描。 |
點陣圖索引的大小比BTREE索引要小的多,所以點陣圖索引掃描快。 |
邏輯讀為5 |
物化檢視 |
CREATE MATERIALIZED VIEW MV_COUNT_T BUILD IMMEDIATE REFRESH ON COMMIT ENABLE QUERY REWRITE AS SELECT COUNT(*) FROM T; |
MAT_VIEW REWRITE ACCESS FULL |
空間換時間。 |
要注意,如果資料要求比較實時,就不適用。 |
邏輯讀為3 |
快取結果 |
SELECT /*+ RESULT_CACHE */ COUNT(*) FROM T; |
RESULT CACHE |
直接把查詢結果拿來用。 |
要注意,如果資料頻繁更新,就不適用。 |
邏輯讀為0 |
業務理解 |
SELECT COUNT(*) FROM T WHERE ROWNUM=1; |
|
如果COUNT(*)只是為了判斷條數,就加上ROWNUM=1來判斷是否為1。 |
業務需求轉換,獲取條數有的時候,只是為了看看錶是否為空,這時候是否是1條和是否大於0其實是一樣的。 |
不言而喻 |
分析需求 |
據說,這個COUNT(*)統計條數語句,是多餘的!直接砍了這條語句,這裡沒有SQL! |
無敵! |
點陣圖索引可以按很高密度儲存資料,因此往往比B樹索引小很多,前提是在基數比較小(列重複度比較高)的情況下。點陣圖索引是儲存空值的,因此可以在COUNT中利用。點陣圖索引不太適合OLTP型別資料庫。物化檢視是應用在資料要求不怎麼及時的場景下。若表頻繁更新,則不適合快取結果集。
優化沒有止境,對資料庫瞭解越多,能想到的方法就越多。
你真的會用索引嗎?來看看COUNT(*)到底能有多快
https://mp.weixin.qq.com/s?__biz=MjM5MDAxOTk2MQ==&mid=2650272185&idx=1&sn=77808908dbeab10781f647932761f475&chksm=be4869af893fe0b9c7a513059e5d979af476e973c5b9f64f6661d3d3ed64e22e61a4d2ff0814&mpshare=1&scene=23&srcid=0704h21rWZZcKqSvJupXJliK#rd編輯手記:韓老師在資料庫效能優化方面有很豐富的經驗,出版書籍《SQL 優化最佳實踐》,感謝韓老師和機械工業出版社的授權,我們會在接下來的每週二分享書中的經典篇章,與大家共同成長。
一個大表的COUNT,究竟能有多快?除類似物化檢視的做法,我們所能做到的極限能有多快?這不是一個真實的案例,而是根據筆者在網上發的一篇帖子整理而來。通過對一條SQL,採用多種方式持續優化過程,表明SQL優化的手段隨著優化者掌握的技能增多,其可能存在的手段也在不斷增多。
1、資料準備
2、全表掃描
全表掃描的程式碼如下(共用124秒,好慢呀):
由上可知,全表掃描耗時較長。
3、主鍵索引
主鍵索引的程式碼如下:
通過引入索引,執行計劃變成索引快速全掃描,因掃描塊數較少,因此耗時也大大減少,共用33秒,快多了。
4、常數索引
常數索引的程式碼如下:
常數索引在儲存密度上要高於普通欄位索引,因此掃描塊數更少,耗時也更少,共耗時29秒。
5、常數壓縮索引
常數壓縮索引的程式碼如下
索引壓縮排一步減少了掃描規模,耗時縮減到27秒。
6、點陣圖索引
點陣圖索引不同於B樹索引,其儲存密度更高。這裡是採用status欄位,如果使用常數索引,其規模將更小。這種手段用時0.9秒,這是質的飛躍。
7、點陣圖索引+並行
並行技術可以較快執行速度。一致性讀有所增加,但並行還是能加快整體執行速度,這種手段耗時0.03秒,竟然又快了不少。
點陣圖索引可以按很高密度儲存資料,因此往往比B樹索引小很多。前提是在基數比較小的情況下。
點陣圖索引是儲存空值的,因此可以在COUNT中利用。
眾所周知,點陣圖索引不太適合OLTP型別資料庫。該例項僅為了測試展示
優化沒有止境,對資料庫瞭解越多,你能想到的方法就越多。
--本文節選自《SQL 優化最佳實踐》第一章。
從簡單Sql探索優化之道
https://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=402867685&idx=1&sn=998efd041af597d3348cc8e74d921a02&mpshare=1&scene=23&srcid=0704kiAC3QEjNgIM454HQ2L9#rd本文需要優化的語句是select count(*) from t,這簡單的統計語句一出,估計不少人納悶了,能有啥優化空間,還優化之道,什麼gui。
哦,其實簡單的背後不簡單,來,跟作者一起看看如何“不擇手段”,讓count(*) 飛起來。不過我們用意的關鍵是讓讀者去思考,為什麼能飛。
為什麼能飛?嗯,因為我們掌握了Sql優化之道。那優化之道是什麼?不著急,來,隨我們來看看Sql飛的過程吧。
一 、優化過程
1. 普通思路
用了啥手段:啥沒用!
效能啥情況:邏輯讀為1048。
2. 增加索引
用了啥手段:建了一個btree索引。
效能啥情況:邏輯讀從1048減少到372。
3. 點陣圖索引
用了啥手段:建了一個點陣圖索引。
效能啥情況:邏輯讀從372瞬間縮減為6。
簡單地說說點陣圖索引的結構,比如T表有4個欄位,分別是ID、NAME、SEX和STATUS,其中SEX取值僅為男或女,有時由於不知道性別,暫時為空,具體如下:
4. 物化檢視
用了啥手段:應用了物化檢視。
效能啥情況:邏輯讀從6縮減為3。
說明:這主要是應用在資料庫更新不是非常頻繁場景,用的是空間換時間。
5. 快取結果集
用了啥手段: 利用快取結果集技術。
效能啥情況:邏輯讀從3縮減為0。
在11g中,Oracle提供了結果集快取特性。該快取是在共享記憶體中儲存全部的結果集,如果一個查詢SQL被執行,且它對應的結果集在快取中,那麼,該SQL的幾乎全部開銷都可以避免。
6. 業務理解迎來速度之王
用了啥手段: 做了一件很奇怪的事,似乎把Sql改寫的看不懂了。
select count(*) from t where rownum=1; |
和下面的邏輯是等價的。
效能啥情況:表不管多大,永遠只訪問第1條,速度問題還需要糾結嗎?
二 、優化總結
三、總結
這本是一個簡單的語句,卻可以神奇的完成一次又一次優化,效能不斷提升,優化過程涵蓋了Sql執行計劃和索引的理解、根據不同場景選擇不同技術、根據業務進行等價改寫這三大技巧,可謂非常的經典。簡單的背後不簡單,充滿了人生的智慧,還請多多體會。
哦,還沒說,Sql優化之道是什麼?嗯,請看下面:
-
優化知識本身+根據場景選擇技術+把握業務需求!
作者介紹:樑敬彬
-
【DBA+社群】資料庫專家。
-
福富研究院副理事長;福富軟體特級專家。
-
公司四星級內訓師、ITPUB版主及ITPUB社群專家,十餘年資料庫設計調優及培訓相關經驗,多次應邀參加中國資料庫技術大會任演講嘉賓。
-
此外還著有多本暢銷資料庫技術書籍,其代表作《收穫,不止Oracle》極為暢銷,上市3個月內就完成第3次印刷。新書《從菜鳥到Sql優化大師》即將上市......
About Me
...............................................................................................................................
● 本文作者:小麥苗,只專注於資料庫的技術,更注重技術的運用
● 本文在itpub(http://blog.itpub.net/26736162)、部落格園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新
● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/
● 本文部落格園地址:http://www.cnblogs.com/lhrbest
● 本文pdf版及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/
● 資料庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/
● QQ群:230161599 微信群:私聊
● 聯絡我請加QQ好友(646634621),註明新增緣由
● 於 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成
● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解
● 版權所有,歡迎分享本文,轉載請保留出處
...............................................................................................................................
拿起手機使用微信客戶端掃描下邊的左邊圖片來關注小麥苗的微信公眾號:xiaomaimiaolhr,掃描右邊的二維碼加入小麥苗的QQ群,學習最實用的資料庫技術。
![]()
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2141601/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JS每日一題: 前端優化手段有哪些JS每日一題前端優化
- Sql優化(二) 快速計算Distinct CountSQL優化
- 雲端計算虛擬化的優劣勢有哪些?
- 電商廣告營銷中,有哪些常見公式和優化手段?公式優化
- count(*) 優化優化
- count(*)優化優化
- count(*)小優化優化
- 【優化】COUNT(1)、COUNT(*)、COUNT(常量)、COUNT(主鍵)、COUNT(ROWID)等優化
- 相親交友原始碼前端效能優化,通常使用哪些手段?原始碼前端優化
- HOME: Count Digits —— 計算字串中數字個數Git字串
- 【MySQL】效能優化之 count(*) VS count(col)MySql優化
- 使用預計算分割槽優化引數化優化
- 學習雲端計算有哪些優勢?雲端計算教程學習路線圖
- MySQL優化COUNT()查詢MySql優化
- MySQL的count(*)的優化,獲取千萬級資料表的總行數MySql優化
- 網站設計扁平化站有哪些優勢?網站
- 併發程式設計之 鎖的優化有哪些程式設計優化
- MySQL百分位數計算(優化版)MySql優化
- 百萬資料 mysql count(*)優化MySql優化
- 行轉列計算差值的一種優化優化
- 一些webpack配置優化手段Web優化
- 前端效能優化的常用手段前端優化
- MySQL百分位數計算(再優化版)MySql優化
- C++ 效能優化篇二《影響優化的計算機行為》C++優化計算機
- 雲端計算教程學習入門影片課件:商業化雲端計算元件有哪些?元件
- 資料庫效能優化有哪些方式資料庫優化
- 頁面效能優化辦法有哪些?優化
- 資料庫效能優化有哪些措施?資料庫優化
- 什麼是勒索軟體?傳播手段有哪些?
- 什麼是雲端計算?雲端計算學習方向有哪些?
- 大資料視覺化有哪些優勢大資料視覺化
- 相對於其他技術而言,雲端計算有哪些相對的優勢?
- Android效能優化篇之計算效能優化Android優化
- 【知識分享】攻擊伺服器的手段有哪些伺服器
- 【案例】MySQL count操作優化案例一則MySql優化
- 優化select count(*) from t1優化
- 多維分析的後臺效能優化手段優化
- java Count如何計算流中的元素Java