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


9

カウント(集計)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]


1
これを1回だけ、または繰り返し行う必要がありますか?
Jon Seigel、2012年

@JonSeigelは増分ロードを実行しており、データベースシステム間のレコードを毎日比較して、カウントが確実に加算されるようにします。だから繰り返し。
MacGyver 2012年

回答:


10

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

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%正確であることが保証されていません。しかし、あなたの質問から、移行後に各テーブルを確認するために行カウントを行っているように思えるので、このクエリはうまくいくはずです。


4
@フィルなぜ?テーブルをループして、それぞれから高価なSELECT COUNT(*)を実行すると、最後のテーブルに到達した後の最初の結果はどのくらい正確ですか?
アーロンバートランド

1
明確にするために、フィルは言った: "100%正確な結果を提供しないデータディクショナリを使用することは悪いアドバイスです。私の意見では、提案を削除するために回答を編集するか、削除する必要があります。カットアンドペースト...」私は免責事項が重要であることに同意します(そして、メタデータが適切な結果を返さないといういくつかのエッジケースがあると言われています)、私は一般的にメタデータビューを使用することは悪いアドバイスだと思いません。
アーロンバートランド

5

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


@SQLKiwi:2012年より前に読み取りがブロックされるのはなぜですか?SQL Serverのバグ?
Jon Seigel、2012年

@JonSeigel-私の$ 0,05:オフラインで作成された通常のテーブルの通常のクラスター化インデックスは、テーブルにSch-Mロックを適用します。ビューではもちろん必要ありません、これはCreate Indexオペレーションを変更して、インデックス付きビューの特別なケースを作成することを意味します-これはSQL2012で行われました。もちろん、私見。
Fabricio Araujo、

3

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

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

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

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

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

alter table mytable parallel 12;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.