webentwicklung-frage-antwort-db.com.de

Schnellere Alternative in Oracle zum Auswählen von COUNT (*) FROM

Ich habe festgestellt, dass in Oracle die Abfrage

SELECT COUNT(*) FROM sometable;

ist für große Tische sehr langsam. Es scheint, als würde die Datenbank tatsächlich jede Zeile durchlaufen und einen Zähler einzeln erhöhen. Ich würde denken, dass es irgendwo in der Tabelle einen Zähler gibt, wie viele Zeilen diese Tabelle hat.

Wenn ich also die Anzahl der Zeilen in einer Tabelle in Oracle überprüfen möchte, wie kann ich das am schnellsten tun?

52
Eli Courtwright

Denken Sie darüber nach: Die Datenbank muss dazu wirklich in jede Zeile gehen. In einer Umgebung mit mehreren Benutzern kann sich meine COUNT(*) von Ihrer COUNT(*) unterscheiden. Es wäre unpraktisch, für jede Sitzung einen anderen Zähler zu haben, so dass Sie die Zeilen buchstäblich zählen müssen. Die meiste Zeit hätten Sie sowieso eine WHERE-Klausel oder ein JOIN in Ihrer Abfrage, so dass Ihr hypothetischer Zähler von etwas praktischem Wert wäre.

Es gibt jedoch Möglichkeiten, die Dinge zu beschleunigen: Wenn Sie einen INDEX in einer NOT NULL-Spalte haben, zählt Oracle die Zeilen des Index anstelle der Tabelle. In einem geeigneten relationalen Modell haben alle Tabellen einen Primärschlüssel, sodass COUNT(*) den Index des Primärschlüssels verwendet.

Der Bitmap-Index enthält Einträge für NULL-Zeilen, sodass ein COUNT (*) einen Bitmap-Index verwendet, falls vorhanden.

27
Vincent Malgrat

Wenn Sie nur eine grobe Schätzung wünschen, können Sie aus einer Stichprobe extrapolieren:

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

Für eine höhere Geschwindigkeit (aber geringere Genauigkeit) können Sie die Stichprobengröße verringern:

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

Für eine noch höhere Geschwindigkeit (aber noch schlechtere Genauigkeit) können Sie die blockweise Abtastung verwenden:

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

53
Jeffrey Kemp

Dies funktioniert gut für große Tische.

SELECT NUM_ROWS FROM ALL_TABLES WHERE TABLE_NAME = 'TABLE_NAME_IN_UPPERCASE';

Für kleine bis mittelgroße Tische ist das Folgen in Ordnung.

SELECT COUNT(Primary_Key) FROM table_name;

Prost,

43
AMISH G SHAH

Wenn die Tabelle einen Index für eine NOT NULL-Spalte enthält, verwendet COUNT (*) diesen. Andernfalls wird ein vollständiger Tabellenscan ausgeführt. Beachten Sie, dass der Index nicht UNIQUE sein muss, sondern nur NOT NULL.

Hier ist ein Tisch ...

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>

Zuerst zählen wir ohne Indexe ....

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>

Nein, wir erstellen einen Index für eine Spalte, die NULL-Einträge enthalten kann ...

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>

Schließlich erstellen wir den Index in der NOT NULL-Spalte ....

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>
13
APC

Option 1: Verfügen Sie über einen Index für eine Nicht-Null-Spalte, die für den Scan verwendet werden kann. Oder erstellen Sie einen funktionsbasierten Index als:

create index idx on t(0);

dieses kann dann gescannt werden, um die Zählung anzugeben.

Option 2: Wenn Sie die Überwachung aktiviert haben, überprüfen Sie die Überwachungssicht USER_TAB_MODIFICATIONS und addieren/subtrahieren Sie die entsprechenden Werte zur Tabellenstatistik.

Option 3: Für eine schnelle Schätzung großer Tabellen rufen Sie die Klausel SAMPLE auf ... zum Beispiel ...

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

Option 4: Verwenden Sie eine materialisierte Ansicht, um die Anzahl zu erhalten (*). Leistungsstarke Medizin.

um ...

7
David Aldridge

Sie können eine materialisierte Ansicht für die schnelle Aktualisierung erstellen, um die Anzahl zu speichern.

Beispiel:

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; 

Mutationen auf dem Tisch werden etwas verlangsamt, aber das Zählen wird viel schneller. 

5
tuinstoel

Der schnellste Weg, eine Tabelle zu zählen, ist genau das, was Sie getan haben. Es gibt keine Tricks, die Oracle noch nicht kennt.

Es gibt Dinge, die Sie uns nicht erzählt haben. Warum sollte es Ihrer Meinung nach schneller sein?

Zum Beispiel:

  1. Haben Sie zumindest einen Erklärungsplan erstellt, um zu sehen, was Oracle tut?
  2. Wie viele Zeilen enthält diese Tabelle?
  3. Welche Oracle-Version verwenden Sie? 8,9,10,11 ... 7?
  4. Haben Sie jemals Datenbankstatistiken für diese Tabelle ausgeführt?
  5. Ist dies eine häufig aktualisierte Tabelle oder ein geladener Stapel oder nur statische Daten?
  6. Ist dies der einzige langsame COUNT (*), den Sie haben?
  7. Wie lange dauert SELECT COUNT (*) FROM Dual?

Ich gebe zu, dass ich mit 41 Sekunden nicht glücklich wäre, aber warum sollte es schneller gehen? Wenn Sie uns sagen, dass der Tisch 18 Milliarden Zeilen hat und auf dem Laptop läuft, den Sie 2001 von einem Flohmarkt gekauft haben, sind 41 Sekunden wahrscheinlich nicht so weit außerhalb von "gut wie er wird", sofern Sie keine bessere Hardware bekommen. Wenn Sie jedoch sagen, dass Sie Oracle 9 verwenden und im letzten Sommer gut Statistiken erstellt haben, werden Sie wahrscheinlich andere Vorschläge erhalten.

3
David

Eine relevante Antwort von Ask Tom wurde im April 2016 veröffentlicht.

Wenn Sie über ausreichende Serverleistung verfügen, können Sie dies tun

select /*+ parallel */ count(*) from sometable

Wenn Sie gerade nach einer Annäherung sind, können Sie Folgendes tun:

select 5 * count(*) from sometable sample block (10);

Auch wenn es gibt

  1. eine Spalte, die keine Nullen enthält, aber nicht als NOT NULL definiert ist, und
  2. es gibt einen Index für diese Spalte

du könntest es versuchen:

select /*+ index_ffs(t) */ count(*) from sometable  t where indexed_col is not null
1
m.r226

Sie können eine bessere Leistung erzielen, indem Sie die folgende Methode verwenden:

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