2014-01-31 49 views
3

我有一些查询已经运行良好多年,但突然它开始减慢了很多。从几乎瞬间到25秒。 经过一番研究后发现问题是“破损”的索引。重新组织和重建查询使用的四个表中的所有索引解决了问题。SQL查询每隔几天放缓

很好,我完全想到。但几天后又出现同样的问题。重建索引固定它,但它每隔几天就开始回来。查询变慢=>重建索引。 表格非常稳定,一周内会添加几百个项目,并且它们具有300k条记录。

这可能是什么原因造成的?

编辑:

这是关于这个查询,我不知道如何使这个更有效,而不破事

ALTER PROCEDURE [dbo].[odat_PricesByDealer] 
(
    @dealer_id   int, 
    @dealergroup_id  int, 
    @startdate   datetime, 
    @pricetype_id  int, 
    @product_groep  nvarchar(30) 
) 
AS 
    SET NOCOUNT ON 

    IF @pricetype_id = 0 
     SET @pricetype_id = NULL 

    IF @product_groep = '0' 
     SET @product_groep = NULL 

    SELECT a.price_ID 
     , a.make_id 
     , e.make_code_name 
     , a.dealergroup_ID 
     , c.product_ID 
     , c.product_code 
     , c.product_department 
     , c.product_code_name  
     , c.product_groep 
     , c.product_subgroep1 
     , c.product_subgroep2 
     , c.product_producent 
     , b.pricerow_lowerbound 
     , b.pricerow_upperbound 
     , b.pricerow_value 
     , aa.startdate AS startdate 
     , a.price_enddate AS enddate 
     , d.pricetype_id 
     , d.pricetype_name 
     , 3 AS price_level 
    FROM dbo.tblPrices a WITH (NOLOCK) 
    JOIN udf_PricesByDealer(@dealer_id, @startdate) aa ON a.price_startdate = aa.startdate 
     AND a.product_id = aa.product_id 
     AND a.pricetype_ID = aa.pricetype_ID 
     AND a.make_ID = aa.make_ID 
     AND a.dealergroup_ID = aa.dealergroup_ID 
     AND a.dealer_ID = aa.dealer_ID 
    JOIN dbo.tblPriceRows b WITH (NOLOCK) ON a.price_ID = b.price_ID 
    JOIN dbo.tblProducts c WITH (NOLOCK) ON a.product_ID = c.product_ID 
    JOIN dbo.tblPriceTypes d WITH (NOLOCK) ON a.pricetype_ID = d.pricetype_ID 
    JOIN dbo.tblMakes e WITH (NOLOCK) ON a.make_ID = e.make_ID 
    WHERE a.make_ID <> 0 
     AND a.dealergroup_ID = @dealergroup_id 
     AND a.dealer_ID = @dealer_id 
     AND (d.pricetype_id = @pricetype_id OR @pricetype_id IS NULL) 
     AND (c.product_groep = @product_groep OR @product_groep IS NULL) 
     AND a.price_authorized = 1 
     AND c.product_exclude_from_pricelist = 0 

和UDF在JOIN看起来像这样

ALTER FUNCTION [dbo].[udf_PricesByDealer] 
(  
    @dealer_ID numeric, 
    @startdate datetime 
) 
RETURNS TABLE 
AS  
RETURN  
(  
    SELECT MAX(a.price_startdate) AS startdate 
     , a.make_id 
     , a.product_id 
     , a.pricetype_id 
     , a.dealergroup_id 
     , a.dealer_id  
    FROM dbo.tblPrices a WITH (NOLOCK) 
    JOIN udf_GetMakeIdForDealer(@dealer_id) b ON a.make_ID = b.make_ID 
    WHERE ((a.price_startdate <= @startdate AND a.price_enddate >= @startdate) 
      OR 
      (a.price_startdate <= @startdate AND a.price_enddate < a.price_startdate)) 
     AND a.make_ID <> 0  
     AND a.dealergroup_id <> 0 
     AND a.dealer_id = @dealer_ID 
    GROUP BY a.make_id 
     , a.product_id 
     , a.pricetype_id 
     , a.dealergroup_id 
     , a.dealer_id   
) 

和UDF上的另一个连接

ALTER FUNCTION [dbo].[udf_GetMakeIdForDealer] 
(
    @dealer_ID numeric 
) 
RETURNS TABLE 
AS 
RETURN 
(
    SELECT m.make_ID 
     , m.make_code_name 
    FROM [dbo].[tblMakes] m WITH (NOLOCK) 
    WHERE (m.make_ID in (SELECT make_ID 
         FROM tblDealerGroupMakes WITH (NOLOCK) 
         WHERE dealergroup_ID = (SELECT dealergroup_ID 
               FROM tblDealers WITH (NOLOCK) 
               WHERE dealer_ID = @dealer_ID)) 
      OR 
      m.make_ID IN (SELECT make_ID 
         FROM tblDealerMakes WITH (NOLOCK) 
         WHERE dealer_ID = @dealer_ID AND dealermake_exclude = 0)) 
     AND m.make_ID NOT IN (SELECT make_ID 
          FROM tblDealerMakes WITH (NOLOCK) 
          WHERE dealer_ID = @dealer_ID AND dealermake_exclude = 1) 
) 
+1

重建索引是第一步。您还可以检查执行计划并查看任何瓶颈,并重构查询以提高性能。如果您将罪魁祸首查询(cies)和执行计划作为屏幕截图发布,您可能会获得更多帮助。 –

+1

你试过'更新统计信息'而不是重建索引吗?不知道这是否会有所帮助,但只是把它放在那里。 http://technet.microsoft.com/en-us/library/ms187348.aspx – Jess

+0

你能不能详述一下'破'索引是什么? –

回答

1

Punter015已发布,您必须调整您的数据库,例如有一个保养计划。因为你不知道是否有必要(我遇到同样的问题一次),我做了一些调查,在网上找到了一些样品,最后做了这个程序。

它检查是否需要reindex,然后执行reindex。我每晚运行一个cron任务(sqlcmd.exe)。不知道这是否是最好的方法,但对我来说工作正常。

CREATE PROCEDURE [dbo].[proc_ReorganizeIndexes] 
AS 
BEGIN 

    DECLARE @table nvarchar(100); 
    DECLARE @index_name nvarchar(100); 
    DECLARE @ext_frag float; 
    DECLARE @int_frag float; 
    DECLARE @sql nvarchar(max); 
    DECLARE local_index_cursor CURSOR FOR 

    SELECT object_name(dt.object_id) Tablename 
     ,si.name IndexName 
     ,dt.avg_fragmentation_in_percent AS ExternalFragmentation 
     ,dt.avg_page_space_used_in_percent AS InternalFragmentation 
    FROM 
    (
     SELECT object_id,index_id,avg_fragmentation_in_percent,avg_page_space_used_in_percent 
     FROM sys.dm_db_index_physical_stats (db_id(DB_NAME()),null,null,null,'DETAILED' 
) 
    WHERE index_id <> 0) AS dt 
    INNER JOIN sys.indexes si ON si.object_id=dt.object_id 
     AND si.index_id=dt.index_id AND dt.avg_fragmentation_in_percent>10 
     AND dt.avg_page_space_used_in_percent<75 ORDER BY avg_fragmentation_in_percent DESC 

    OPEN local_index_cursor 
    FETCH NEXT FROM local_index_cursor 
    INTO @table, @index_name, @ext_frag, @int_frag 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 

     PRINT 'Need rebuild: ' + @table+ ' for index ' + @index_name + ' Fragmentation (int/ext): ' + CAST(@int_frag AS varchar(100)) + '/' + CAST(@ext_frag AS varchar(100)) 
    SET @sql = 'ALTER INDEX ALL ON ' + @table + ' REBUILD WITH (FILLFACTOR=90)' 
     EXEC sp_executesql @sql 

     FETCH NEXT FROM local_index_cursor 
     INTO @table, @index_name, @ext_frag, @int_frag 
    END 

    CLOSE local_index_cursor 
    DEALLOCATE local_index_cursor 

END 
+0

不错,会用这个。谢谢 – Laurijssen

1

如果索引中的碎片较少,您可以重新组织索引,如果不是重建索引。如果重建索引解决了您的问题,请在实例上相应地创建一个索引维护计划,以便进行适当的索引维护。如果在相关数据库上启用自动更新统计信息,则也会更新统计信息。

主要方面是调整查询。