web-dev-qa-db-ja.com

SQLカウントクエリを高速化できるものは何ですか?

カウント(集計)SQLクエリを実行する場合、これら3つのデータベースシステムで実行時間を短縮できるものは何ですか?スピードアップできるものはたくさんあると思いますが(ハードウェアは1つです)、私は初心者のDBAなので、ここでいくつかの回答を得られると確信しています。約1億5700万行をSQL​​ Serverデータベースに移行しましたが、このクエリは永遠にかかります。しかし、私のソースのNetezzaデータベースでは、数秒かかります。

例:

Netezza 6:

SELECT COUNT(*) FROM DATABASENAME..MYTABLE

Oracle 11g:

SELECT COUNT(*) FROM MYTABLE

SQL Server 2012:

SELECT COUNT(*) FROM DATABASENAME.[dbo].[MYTABLE]
9
MacGyver

Netezzaは、大規模なテーブルスキャンでExcelを使用するように設計されたアプライアンスです。そのため、そのシステムで非常に高速な結果が得られます。

SQL Serverの場合、sys.dm_db_partition_stats DMVからクエリを実行することで、行数を大幅に高速化できます。

SELECT s.name AS [Schema], o.name AS [Table], SUM(p.row_count) AS [RowCount]
FROM sys.dm_db_partition_stats p JOIN sys.objects o
ON p.object_id = o.object_id JOIN sys.schemas s
ON o.schema_id = s.schema_id
WHERE p.index_id < 2
AND o.object_id = object_id('MyTable')
GROUP BY o.name, s.name;

高トランザクション環境では、このDMVは100%正確であることが保証されていません。しかし、あなたの質問から、移行後に各テーブルを確認するために行カウントを行っているように思えるので、このクエリはうまくいくはずです。

10
Patrick Keisler

次に、インデックス付きビュー内でCOUNT_BIGを使用するSQL Serverソリューションを示します。これにより、大きなテーブルスキャンやインデックススキャンのオーバーヘッドがなく、後者に必要なストレージを必要とせずに、トランザクション的に一貫したカウントが得られます。

CREATE TABLE [dbo].[MyTable](id int);
GO

CREATE VIEW [dbo].[MyTableRowCount]
    WITH SCHEMABINDING
AS

    SELECT
        COUNT_BIG(*) AS TableRowCount
        FROM [dbo].[MyTable];
GO

CREATE UNIQUE CLUSTERED INDEX IX_MyTableRowCount
    ON [dbo].[MyTableRowCount](TableRowCount);
GO

SELECT
    TableRowCount
    FROM [dbo].[MyTableRowCount] WITH(NOEXPAND);

これには、1回の初期スキャンが必要で(これを回避する必要はありません)、増分テーブルデータ操作に少しのオーバーヘッドが追加されます。多数の小さな操作ではなく、大量のデータを使用して大きな操作を実行している場合、変更のオーバーヘッドは無視できると思います。

5
Jon Seigel

Oracleでは、単純なカウントクエリは多くの場合、テーブル全体ではなくインデックスをスキャンして実行されます。インデックスはビットマップインデックスであるか、NOT NULL制約のある列で定義されている必要があります。全テーブルスキャンを必要とするより複雑なクエリの場合は、並列クエリを使用できます。

並列クエリを有効にするには(Enterprise Editionが必要です)、オプティマイザヒントを使用できます。

select /*+ PARALLEL(mytable, 12) */ count(*) from mytable;

または、テーブルのすべてのクエリに対して並列クエリを有効にします。

alter table mytable parallel 12;
3
sjk

Oracleでは、NOT NULL列のバイナリツリーインデックスを使用して、COUNT(*)に応答できます。インデックスは通常、ベーステーブルよりも小さいため、ほとんどの場合、FULL TABLE SCANよりも高速です。

ただし、通常のバイナリツリーインデックスは依然として157 Mrowsと巨大です。 テーブルが同時に更新されない場合(つまり、バッチロードプロセスのみ)、代わりにビットマップインデックスを使用できます。

最小のビットマップインデックスは次のようになります。

CREATE BITMAP INDEX ix ON your_table(NULL);

Nullエントリは、ビットマップインデックスによって考慮されます。結果のインデックスは、通常のバイナリツリーインデックスまたはベーステーブルのいずれかに比べて、非常に小さくなります(100万行あたり20〜30個の8kブロック)。

結果の計画には、次の操作が表示されます。

----------------------------------------------
| Id  | Operation                     | Name | 
----------------------------------------------
|   0 | SELECT STATEMENT              |      |
|   1 |  SORT AGGREGATE               |      |
|   2 |   BITMAP CONVERSION COUNT     |      |
|   3 |    BITMAP INDEX FAST FULL SCAN| IX   |
----------------------------------------------

テーブルが同時に更新される場合は、一意の値を持つビットマップインデックスが競合のポイントになるため、使用しないでください。

3
Vincent Malgrat