1

我在 SQL Server 2008 数据库中有一个非常大的表,包含 4000 万行。

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

unique_id尝试用一个单独的(假设它确实是唯一的)替换您的聚集索引(当前在两列上)。这将有助于您的排序。然后添加第二个覆盖索引 - 正如您已经尝试过的那样 - 在WHERE. 检查您的统计数据是否是最新的。我有一种感觉,bar_code您的 PK 中的列正在阻止您的排序尽可能快地运行。

您的变量是否包含通配符?如果包含,并且它们是前导通配符,则不能使用 WHERE 列上的索引。如果它们不是通配符,请尝试直接"=",假设区分大小写不是问题。

更新:由于您有前导通配符,您将无法利用CONTRACT_NUMBER,INVOICE_NUMBERCUSTOMER_NAME: 上的索引,正如 GriGrim 建议的那样,这里唯一的选择是使用全文搜索(CONTAINS关键字等)。

于 2013-10-09T09:32:26.420 回答