1

SQL Server 2008 データベースに、4,000 万行からなる非常に大きなテーブルがあります。

CREATE TABLE [dbo].[myTable](
    [ID] [bigint] NOT NULL,
    [CONTRACT_NUMBER] [varchar](50) NULL,
    [CUSTOMER_NAME] [varchar](200) NULL,
    [INVOICE_NUMBER] [varchar](50) NULL,
    [AGENCY] [varchar](50) NULL,
    [AMOUNT] [varchar](50) NULL,
    [INVOICE_MONTH] [int] NULL,
    [INVOICE_YEAR] [int] NULL,
    [Unique_ID] [bigint] NULL,
    [bar_code] [varchar](50) NOT NULL,
 CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED 
(
    [ID] ASC,
    [bar_code] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

次のクエリのパフォーマンスを最適化しようとしています。

SELECT top 35  ID,
            CONTRACT_NR,
            CUSTOMER_NAME,
            INVOICE_NUMBER,
            AMOUNT,
            AGENCY,
            CONTRACT_NUMBER,
            ISNULL([INVOICE_MONTH], 1) as [INVOICE_MONTH],
            ISNULL([INVOICE_YEAR], 1) as [INVOICE_YEAR],
            bar_code, 
            Unique_ID
            from MyTable 
WHERE 
CONTRACT_NUMBER like @CONTRACT_NUMBER and
INVOICE_NUMBER like @INVOICE_NUMBER and 
CUSTOMER_NAME like @CUSTOMER_NAME 
ORDER BY Unique_ID desc

そのために、列 CONTRACT_NUMBER、INVOICE_NUMBER、および CUSTOMER_NAME にインクルード インデックスを作成します。

CREATE NONCLUSTERED INDEX [ix_search_columns_without_uniqueid] ON [dbo].[MyTable] 
(
    [CONTRACT_NUMBER] ASC,
    [CUSTOMER_NAME] ASC,
    [INVOICE_NUMBER] ASC
)
INCLUDE ( [ID],
[AGENCY],
[AMOUNT],
[INVOICE_MONTH],
[INVOICE_YEAR],
[Unique_ID],
[Contract_nr],
[bar_code]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

それでも、クエリの実行には 3 秒から 10 秒かかります。クエリ実行プランから、インデックス シーク操作が全体のワークロードの約 30% を消費し、ソート (トップ N) 操作が残りの 70% を消費していることがわかります。このクエリを最適化するにはどうすればよいですか? 1 秒未満の応答時間をお勧めします。注: インデックス列に列 [Unique_ID] も含めようとしました。この場合、クエリ実行プランはインデックス スキャンを実行していますが、多くのユーザーがデータベースにクエリを実行しているため、同じ問題が発生しています。

4

2 に答える 2

1

詳細については、このページを確認してください。

  • オプティマイザの作業を容易にするために、フル スキャンで統計を更新します。

UPDATE STATISTICS tablename WITH fullscan GO

  • 統計時間をオンに設定し、次のクエリを実行します

    SET STATISTICS time ON GO
    SELECT num_of_reads, num_of_bytes_read, num_of_writes, num_of_bytes_written FROM sys.dm_io_virtual_file_stats(DB_ID('tempdb'), 1) GO SELECT TOP 100 c1, c2,c3 FROM yourtablename WHERE c1<30000 ORDER BY c2 GO SELECT num_of_reads, num_of_bytes_read, num_of_writes, num_of_bytes_written FROM sys.dm_io_virtual_file_stats(DB_ID('tempdb'), 1) GO

結果

CPU time = 124 ms,  elapsed time = 91 ms
Before Query execution 
num_of_reads         num_of_bytes_read    num_of_writes     num_of_bytes_written
-------------------- -------------------- -------------------- --------------------
725864               46824931328          793589               51814416384
After Query execution  
num_of_reads         num_of_bytes_read    num_of_writes        num_of_bytes_written
-------------------- -------------------- -------------------- --------------------
725864               46824931328          793589               51814416384

ソース: https://www.mssqltips.com/sqlservertip/2053/trick-to-optimize-top-clause-in-sql-server/

于 2016-07-04T04:56:20.753 に答える
0

クラスター化されたインデックス (現在 2 つの列) を 1 つだけのものに置き換えてみてくださいunique_id(それが本当に一意であると仮定します)。これは、並べ替えに役立ちます。次に、2 番目のカバリング インデックスを (試したように) WHERE、. 統計が最新であることを確認してください。PKの列が原因で、並べ替えができるだけ速く実行されていないように感じbar_codeます。

変数にワイルドカードが含まれていますか?ワイルドカードが含まれている場合、WHERE 列のインデックスは使用できません。それらがワイルドカード化されていない場合は"="、大文字と小文字の区別が問題にならないと仮定して、 direct を試してください。

UPDATECONTRACT_NUMBER :先頭にワイルドカードがあるため、 、INVOICE_NUMBERまたはのインデックスを利用することはできませんCUSTOMER_NAME。GriGrim が提案したように、ここでの唯一の代替手段は全文検索 (CONTAINSキーワードなど) を使用することです。

于 2013-10-09T09:32:26.420 に答える