日期:2014-05-18  浏览次数:20494 次

数据表分区添加分区索引后查询很慢
销售数据表TH_ORDER每天差不多都会有40万行新的数据产生,而这些数据都是凌晨从指定的DB中同步过来。由于数据量过大,故将数据库进行分区。
  TH_ORDER表中没有主键列,BUSINESS_DATE列为营业日期,不包含时分秒,也就是每天差不多有40万条相同的营业日期的数据。首先创建了分区函数如下
CREATE PARTITION FUNCTION pf_BUSINESS_DATE(SMALLDATETIME)
 AS RANGE RIGHT FOR VALUES
(
  '2012-01-01',
  '2012-02-01',
  '2012-03-01',
  '2012-04-01',
  '2012-05-01',
  '2012-06-01',
  '2012-07-01',
  '2012-08-01',
  '2012-09-01',
  '2012-10-01',
  '2012-11-01',
  '2012-12-01'

分区架构

CREATE PARTITION SCHEME ps_BUSINESS_DATE  
AS PARTITION pf_BUSINESS_DATE  
TO ([PRIMARY],FG1, FG2, FG3,FG4, FG5, FG6,FG7, FG8, FG9,FG10, FG11, FG12) 

由于Order表中已经存在数据。故给BUSINESS_DATE添加索引如下及分区架构:
CREATE NONCLUSTERED INDEX [IX_TH_ORDER_BUSSINESS_DATE] ON [dbo].[TH_ORDER] 
(
[BUSINESS_DATE] DESC
) ON ps_BUSINESS_DATE([BUSINESS_DATE])

当表中有新数据也就是40万行新数据时,对表执行查询前一天的营业数据(新数据),会变的异常的慢,半个小时都不出数据,而查询前几天的数据就挺正常的。
所以就将索引删除后再添加:
DROP INDEX TH_ORDER.IX_TH_T_ORDER_BUSSINESS_DATE

CREATE NONCLUSTERED INDEX [IX_TH_ORDER_BUSSINESS_DATE] ON [dbo].[TH_ORDER] 
(
[BUSINESS_DATE] DESC
) ON ps_BUSINESS_DATE([BUSINESS_DATE])
这样查询前一天的营业数据挺正常的,为啥重新创建索引后查询就正常了。

这该怎么优化呢?

------解决方案--------------------
如果你是想要按营业日期 BUSINESS_DATE 列对表进行分区,首先表里原来的聚集索引需要Drop,然后按照分区架构对 BUSINESS_DATE 建立聚集索引。
可是我看你的索引创建语句,建的非聚集索引,这样你表中数据应该没有分区。你可以看看文件组对应文件的大小,是否数据已经存在文件中了。
------解决方案--------------------
对于销售数据表,你经常的查询条件应该有时间条件吧,如果是的话,我建议你还是按营业日期 BUSINESS_DATE 列建聚集索引,对表中数据进行分区,然后再对经常查询,重复性不高的某列利用同样的分区架构建立非聚集索引,这样在查询时加上分区条件与新建索引的过滤条件,应该能提升性能。
------解决方案--------------------
最直接的办法,LZ看一下查询的语句 Ctrl+L 看一下执行计划。 里面如果没有用到分区索引,那你的查询当然会慢 。

如果Business_date 是第一个条件的话,而每天都会有40W 我建议LZ在 Business_date字段上建立聚集索引,而且是分区的。(这样可以用到分区索引,直接指向相应分区) 

然后对应其它查询条件使用非聚集索引。 可以更精确定位单一数据。

参考.
------解决方案--------------------
你在测试查询性能是有没有清除缓存数据啊?
另外你的查询语句能否贴出来以下?
------解决方案--------------------
建议:
CREATE CLUSTERED INDEX [IX_TH_ORDER_BUSSINESS_DATE] ON [dbo].[TH_ORDER]
(
[BUSINESS_DATE] DESC
) ON ps_BUSINESS_DATE([BUSINESS_DATE])

即将索引改为聚集分区,这样会将表也作了分区。
注意,聚集索引并不一定需要唯一。

------解决方案--------------------

SQL code
SELECT MR.myRegionId
    , MR.myRegionDes AS MYRegion
    , b.branchId
    ,b.sap_outlet
    ,B.sap_name
    ,b.bdes AS ShopName
    ,I.ItemId AS ITEM_CODE
    ,I.ItemName
    ,SUM(O.QTY) QTY
    ,SUM(O.AMT-O.ITEM_DISC-O.CAT_DISC-O.ORDER_DISC) AMT
    ,O.REGION
    ,O.BUSINESS_DATE
 FROM (    select    ITEM_CODE, REGION , BUSINESS_DATE, OUTLET, TABLE_NUM, QTY, AMT, ITEM_DISC, CAT_DISC, ORDER_DISC
        from    TH_ORDER
        WHERE    BUSINESS_DATE BETWEEN '2012-04-16' AND '2012-04-16' 
            AND TYPE = 'N') O
    LEFT JOIN ING_ITEM I ON O.ITEM_CODE=I.ItemId AND O.REGION=I.REGION AND O.BUSINESS_DATE=I.BUSINESS_DATE
    LEFT JOIN branch B ON B.branchId=O.OUTLET
    LEFT JOIN myRegion MR ON MR.myRegionId=B.myregionId
    LEFT JOIN JI_table tb ON O.OUTLET= tb.OUTLET and O.TABLE_NUM=tb.ROOM_NUM
    LEFT JOIN CT_OUTLET_FLOOR ct ON tb.OUTLET=ct.OUTLET and tb.FLOOR=ct.FLOOR 
 GROUP BY MR.myRegionId, MR.myRegionDes,b.branchId,b.sap_outlet,B.sap_name,b.bdes,I.ItemId,I.ITEMNAME,O.REGION,O.BUSINESS_DATE;
--你看着这样会不会快点,另外 TYPE='N' 数据在40万里面占百分数?能否建立索引,如果是SQL 2008可以建立条件索引,如下:
crteate index IX_TH_ORDER_TYPE
on TH_ORDER(TYPE)
where TYPE = 'N';
如果是sql2005及以下,以上索引不支持,如果值不多,不适合建索引。