COUNT(*)計算行數有哪些優化手段

lhrbest發表於2017-07-04

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、資料準備

COUNT(*)計算行數有哪些優化手段


2、全表掃描

全表掃描的程式碼如下(共用124秒,好慢呀):

COUNT(*)計算行數有哪些優化手段

由上可知,全表掃描耗時較長。


3、主鍵索引

主鍵索引的程式碼如下:COUNT(*)計算行數有哪些優化手段


通過引入索引,執行計劃變成索引快速全掃描,因掃描塊數較少,因此耗時也大大減少,共用33秒,快多了。


4、常數索引

常數索引的程式碼如下:

COUNT(*)計算行數有哪些優化手段


常數索引在儲存密度上要高於普通欄位索引,因此掃描塊數更少,耗時也更少,共耗時29秒。


5、常數壓縮索引

常數壓縮索引的程式碼如下

COUNT(*)計算行數有哪些優化手段


索引壓縮排一步減少了掃描規模,耗時縮減到27秒


6、點陣圖索引

COUNT(*)計算行數有哪些優化手段


點陣圖索引不同於B樹索引,其儲存密度更高。這裡是採用status欄位,如果使用常數索引,其規模將更小。這種手段用時0.9秒,這是質的飛躍。


7、點陣圖索引+並行

COUNT(*)計算行數有哪些優化手段


並行技術可以較快執行速度。一致性讀有所增加,但並行還是能加快整體執行速度,這種手段耗時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. 普通思路


用了啥手段:啥沒用!


COUNT(*)計算行數有哪些優化手段


效能啥情況:邏輯讀為1048。


2. 增加索引


用了啥手段:建了一個btree索引。


COUNT(*)計算行數有哪些優化手段


效能啥情況:邏輯讀從1048減少到372。


3. 點陣圖索引


用了啥手段:建了一個點陣圖索引。


COUNT(*)計算行數有哪些優化手段


效能啥情況:邏輯讀從372瞬間縮減為6。


簡單地說說點陣圖索引的結構,比如T表有4個欄位,分別是ID、NAME、SEX和STATUS,其中SEX取值僅為男或女,有時由於不知道性別,暫時為空,具體如下:


COUNT(*)計算行數有哪些優化手段

COUNT(*)計算行數有哪些優化手段


4. 物化檢視


用了啥手段:應用了物化檢視。


COUNT(*)計算行數有哪些優化手段


效能啥情況:邏輯讀從6縮減為3。


說明:這主要是應用在資料庫更新不是非常頻繁場景,用的是空間換時間。


5. 快取結果集


用了啥手段: 利用快取結果集技術。


COUNT(*)計算行數有哪些優化手段


效能啥情況:邏輯讀從3縮減為0。


在11g中,Oracle提供了結果集快取特性。該快取是在共享記憶體中儲存全部的結果集,如果一個查詢SQL被執行,且它對應的結果集在快取中,那麼,該SQL的幾乎全部開銷都可以避免。


6. 業務理解迎來速度之王


用了啥手段: 做了一件很奇怪的事,似乎把Sql改寫的看不懂了。


select count(*) from t where rownum=1;


COUNT(*)計算行數有哪些優化手段
 

和下面的邏輯是等價的。


COUNT(*)計算行數有哪些優化手段
 

效能啥情況:表不管多大,永遠只訪問第1條,速度問題還需要糾結嗎? 


二 、優化總結


COUNT(*)計算行數有哪些優化手段


三、總結


這本是一個簡單的語句,卻可以神奇的完成一次又一次優化,效能不斷提升,優化過程涵蓋了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群,學習最實用的資料庫技術。

COUNT(*)計算行數有哪些優化手段
DBA筆試面試講解
歡迎與我聯絡

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2141601/,如需轉載,請註明出處,否則將追究法律責任。

相關文章