programing

Oracle에서 SELECT Count(*) From Somethable을 대체하는 빠른 방법

lastmemo 2023. 3. 27. 20:57
반응형

Oracle에서 SELECT Count(*) From Somethable을 대체하는 빠른 방법

Oracle에서 쿼리는

SELECT COUNT(*) FROM sometable;

큰 테이블치고는 매우 느립니다.실제로 모든 행을 통과하고 카운터를 한 번에 하나씩 증가시키는 데이터베이스인 것 같습니다.테이블 어딘가에 테이블이 몇 줄이나 있는지 카운터가 있을 겁니다.

Oracle에서 테이블의 행 수를 확인하려면 어떻게 하면 가장 빨리 확인할 수 있을까요?

대략적인 추정치만 원한다면 표본에서 다음과 같이 추정할 수 있습니다.

SELECT COUNT(*) * 100 FROM sometable SAMPLE (1);

속도를 높이려면(정확도는 낮지만) 샘플 크기를 줄일 수 있습니다.

SELECT COUNT(*) * 1000 FROM sometable SAMPLE (0.1);

훨씬 더 빠른 속도(그러나 정확도가 더 낮음)를 위해 블럭별 표본 추출을 사용할 수 있습니다.

SELECT COUNT(*) * 100 FROM sometable SAMPLE BLOCK (1);

이것은 큰 테이블에 매우 적합합니다.

SELECT NUM_ROWS FROM ALL_TABLES WHERE TABLE_NAME = 'TABLE_NAME_IN_UPPERCASE';

중소형 테이블에 대해서는, 이하와 같이 해 주세요.

SELECT COUNT(Primary_Key) FROM table_name;

건배.

생각해 보세요.데이터베이스는 실제로 모든 행으로 이동해야 합니다.다중 사용자 환경에서는 사용자와는 다를있습니다.각 세션에 대해 다른 카운터를 갖는 것은 비현실적이기 때문에 말 그대로 행을 셀 수밖에 없습니다.대부분의 경우 질문에는 WHERE 절이나 JOIN이 있기 때문에 가상 카운터가 실용적으로 가치가 있습니다.

그러나 속도를 높이는 방법이 있습니다. NOT NULL 열에 INDEX가 있는 경우 Oracle은 테이블 대신 인덱스의 행을 계산합니다. 테이블이 있기 에, 「 」는 「 」를 참조해 주세요.COUNT(*)는 프라이머리 키의 인덱스를 사용합니다.

비트맵 인덱스에는 NULL 행에 대한 항목이 있으므로 사용 가능한 비트맵 인덱스가 있는 경우 카운트(*)에서 비트맵 인덱스를 사용합니다.

테이블의 NOT NULL 열에 인덱스가 있는 경우 COUNT(*)는 이를 사용합니다.그렇지 않으면 전체 테이블 검색이 실행됩니다.색인이 고유할 필요는 없으며 NOT NULL이면 됩니다.

여기 테이블이 있는데...

SQL> desc big23
 Name                                      Null?    Type
 ----------------------------------------- -------- ---------------------------
 PK_COL                                    NOT NULL NUMBER
 COL_1                                              VARCHAR2(30)
 COL_2                                              VARCHAR2(30)
 COL_3                                              NUMBER
 COL_4                                              DATE
 COL_5                                              NUMBER
 NAME                                               VARCHAR2(10)

SQL>

먼저 인덱스를 사용하지 않고 카운트를 수행합니다.

SQL> explain plan for
  2      select count(*) from big23
  3  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /
select * from table)dbms_xplan.display)

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
Plan hash value: 983596667

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |  1618   (1)| 00:00:20 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| BIG23 |   472K|  1618   (1)| 00:00:20 |
--------------------------------------------------------------------

Note

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
   - dynamic sampling used for this statement

13 rows selected.

SQL>

아니요, NULL 항목을 포함할 수 있는 열에 인덱스를 만듭니다.

SQL> create index i23 on big23(col_5)
  2  /

Index created.

SQL> delete from plan_table
  2  /

3 rows deleted.

SQL> explain plan for
  2      select count(*) from big23
  3  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
Plan hash value: 983596667

--------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Cost (%CPU)| Time     |
--------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |     1 |  1618   (1)| 00:00:20 |
|   1 |  SORT AGGREGATE    |       |     1 |            |          |
|   2 |   TABLE ACCESS FULL| BIG23 |   472K|  1618   (1)| 00:00:20 |
--------------------------------------------------------------------

Note

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
   - dynamic sampling used for this statement

13 rows selected.

SQL>

마지막으로 NOT NULL 열에 인덱스를 구축합니다.

SQL> drop index i23
  2  /

Index dropped.

SQL> create index i23 on big23(pk_col)
  2  /

Index created.

SQL> delete from plan_table
  2  /

3 rows deleted.

SQL> explain plan for
  2      select count(*) from big23
  3  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------
Plan hash value: 1352920814

----------------------------------------------------------------------
| Id  | Operation             | Name | Rows  | Cost (%CPU)| Time     |
----------------------------------------------------------------------
|   0 | SELECT STATEMENT      |      |     1 |   326   (1)| 00:00:04 |
|   1 |  SORT AGGREGATE       |      |     1 |            |          |
|   2 |   INDEX FAST FULL SCAN| I23  |   472K|   326   (1)| 00:00:04 |
----------------------------------------------------------------------

Note

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------
   - dynamic sampling used for this statement

13 rows selected.

SQL>

옵션 1: 검색에 사용할 수 있는 Null이 아닌 열에 인덱스가 있어야 합니다.또는 다음과 같이 함수 기반 인덱스를 만듭니다.

create index idx on t(0);

그런 다음 이를 스캔하여 카운트를 제공할 수 있습니다.

옵션 2: 모니터링이 켜져 있는 경우 모니터링 뷰 USER_를 확인합니다.TAB_MODICTIONS 및 관련 값을 테이블 통계 정보에 추가/감산합니다.

옵션 3: 큰 테이블에 대한 빠른 견적을 위해 SAMPLE 절을 호출합니다.예를 들면...

SELECT 1000*COUNT(*) FROM sometable SAMPLE(0.1); 

옵션 4: 구체화된 뷰를 사용하여 카운트(*)를 유지합니다.강력한 약이지만.

음...

빠르게 새로 고침 구체화된 뷰를 생성하여 카운트를 저장할 수 있습니다.

예:

create table sometable (
id number(10) not null primary key
, name varchar2(100) not null);

create materialized view log on sometable with rowid including new values;

create materialized view sometable_count
refresh on commit
as
select count(*) count
from   sometable;

insert into sometable values (1,'Raymond');
insert into sometable values (2,'Hans');

commit;

select count from sometable_count; 

테이블에 있는 돌연변이는 조금 늦춰지지만 계산은 훨씬 빨라집니다.

테이블 카운트를 얻는 가장 빠른 방법은 정확히 당신이 한 것입니다.Oracle이 아직 모르는 기술은 없습니다.

당신이 우리에게 말하지 않은 것들이 있다.즉, 당신은 왜 이것이 더 빨라져야 한다고 생각합니까?

예를 들어 다음과 같습니다.

  1. Oracle이 무엇을 하고 있는지 알아보기 위한 설명 계획이라도 세웠습니까?
  2. 이 테이블에는 몇 줄이나 있습니까?
  3. 어떤 버전의 Oracle을 사용하고 있습니까? 8, 9, 10, 11 ... 7?
  4. 이 테이블에서 데이터베이스 통계를 실행한 적이 있습니까?
  5. 이것은 자주 갱신되는 테이블입니까, 배치 로드된 데이터입니까, 아니면 정적 데이터입니까?
  6. 느린 카운트(*)는 이것뿐입니까?
  7. 듀얼에서 SELECT 카운트(*)까지 걸리는 시간은?

41초면 행복하지 않을 것 같은데 왜 더 빨라야 한다고 생각하세요?테이블에는 180억 행이 있으며 2001년 창고 세일에서 구입한 노트북으로 가동되고 있다고 하면 하드웨어가 개선되지 않는 한 41초가 그리 오래 걸리지 않을 것입니다.그러나 Oracle 9을 사용하고 있으며 지난 여름에 통계를 잘 실행했다고 하면 다른 제안을 받을 수 있습니다.

이것은 나에게 잘 작동했다.

select owner, table_name, nvl(num_rows,-1) 
from all_tables 
--where table_name in ('cats', 'dogs')
order by nvl(num_rows,-1) desc

https://livesql.oracle.com/apex/livesql/file/content_EPJLBHYMPOPAGL9PQAV7XH14Q.html 에서

다음 방법을 사용하면 성능을 향상시킬 수 있습니다.

SELECT COUNT(1) FROM (SELECT /*+FIRST_ROWS*/ column_name 
FROM table_name 
WHERE column_name = 'xxxxx' AND ROWNUM = 1);

대신 COUNT(1)를 사용할 수 있습니다.

언급URL : https://stackoverflow.com/questions/1840538/faster-alternative-in-oracle-to-select-count-from-sometable

반응형