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

SQL很有技术含量的问题,达人请进。。10万数据量查询居然要50秒
大概情况是这样的。。数据库里数据量有10万条,要做很复杂的统计操作。。
所以我的做法如下:
1. 将这10万条数据按照日期筛选后放入临时表#A

2.建了一个返回结果的临时表#B

3.每次查询到一部分数据就对#B动态添加一列,然后更新数据

4。一共有16列,所以要查询#A 16次。。

因为查询比较复杂,所以没法用SQL搞出结果,所以只能一列一列这样添加,貌似性能很差。。

现在的情况是第一次查询要50秒。。。 以后每次只需要4秒。。。这个是为什么? 还有有没有优化的方法。。

------解决方案--------------------
1.是否可以一次性将16列选出,做一次更新?
2.是否在日期列上建立索引?
按照道理说,10W数据,不至于这么差的.
可能的话,写出相应的表结构和脚本看看.
------解决方案--------------------
我觉得,最主要的还是要把业务处理的逻辑优化一下。
第一次是50S,因为要建立表,插入数据,修改表结构等,后面时间短可能是因为不需要这个DDL操作了,也有可能是缓存中有了相应的数据
------解决方案--------------------
SQL code
--建议:
--1.sql server 2005支持 select top (@变量) * from tb 的形式,可以将动态语句变为静态,例如:
    INSERT INTO  #TempSecontSortTable
          SELECT A.LCSORT2,B.SortName,A.SORTCOUNT
          From 
          (select TOP (@SecondSortNum) LCSORT2,COUNT(LCSORT2) AS SORTCOUNT 
            FROM #TempLcInfo 
            GROUP BY LCSORT2 ORDER BY sortcount DESC
           ) A,
          dic_LcSort2 B where A.LCSORT2=B.ID ORDER BY A.sortcount DESC

--2.去除在为临时表增加字段时的默认值设置,如果设置默认值,那么在创建这个字段的时候会向这个字段全部写一遍默认值,降低了效率


--先提这两点,楼主看着修改一下吧。

------解决方案--------------------
SQL2000?SQL 2005?
大概看了一下,
SQL2005的话,可以使用Top + 变量,
ROW_NUMBER等对你的数据进行分组处理,
另外,临时表使用的太多了,
看看是否可以减少一些。
------解决方案--------------------
和尚说的有道理呀。

楼主可以从下面几个地方着手。
1.尽量减少临时表。
2.减少动态SQL的使用
3.优化业务逻辑。

因为对你的业务不了解,所以只能说到这了。

------解决方案--------------------
SQL code

 Declare @MinTime datetime  --数据库中最小的日期
    Declare @MaxTime datetime  --数据库中最大的日期
    SELECT @MinTime=Min(LcCreateTime) from tbl_lcinfo
    SELECT @MaxTime=Max(LcCreateTime) from tbl_lcinfo

/*
ashzs:

1、@MinTime和@MaxTime的取值过早,如果@BeginTime和@EndTime都不为null,岂不是白白浪费了两次查询?
2、tbl_lcinfo是不是有针对LcCreateTime的索引?索引问题不再重复提起。

*/    
    --验证输入参数有效性
    IF @BeginTime IS NULL
       SET @BeginTime=@MinTime
    IF @EndTime IS NULL
      SET @EndTime=@MaxTime

    DECLARE @SecondSortNum int --取二级分类数量
    SET @SecondSortNum=4

    DECLARE @ThirdSortNum int  --取三级分类数量
    SET @ThirdSortNum=3

    DECLARE @StreetNum int     --街道数量
    SET @StreetNum=13

/*
ashzs:
1、LcSort1和LcCreateTime字段从来没有用过,为什么要创建?
2、LcID为什么需要设置为主键?在INSERT INTO #TempLcInfo的时候会出现主键重复的情况?tbl_LcInfo中的LcID不是主键吗?
如果是,这里根本不需要设置主键。如果说是为了提高效率,后面的查询也没看到能够使用LcID提高效率的地方。
3、不判断临时表是否存在就直接创建?你后面的drop table有可能因为中途异常不能运行啊。
*/
    --创建临时信息表
    Create table #TempLcInfo
    (
        LcID  varchar(20) not null primary key,
        LcSort1 int,
        LcSort2 int,
        LcSort3 int,
        DealDept varchar(40),
        LcCreateTime datetime
    )
/*
ashzs:
tbl_LcInfo上有针对LcCreateTime的索引吗?tbl_LcInfo上字段多吗?如果字段很多,请考虑索引覆盖。

*/    
   --插入数据
    INSERT INTO #TempLcInfo 
      SELECT LcID,LcSort1,LcSort2,LcSort3,DealDept,LcCreateTime
      From tbl_LcInfo where LcCreateTime Between @BeginTime and @EndTime
    
/*
ashzs:

1、SortName和SortCount在算法中也没有用到啊,为了最后的返回结果集?
2、SortID为什么是unique?保证唯一?但是如果不唯一的话你有错误处理吗?如果是为了提高查询,SortID根本不需要加唯一索引。
   只是一个unqiue,你的SortID值就要存储两份。
   
后面的临时表不再为你检查是否有不需要的字段\unique。依例改之。   
*/
    --创建临时表,保存数量最多的二级分类ID
    Create table  #TempSecontSortTable
    (
       ID        int identity(1,1),
       SortID    int unique,
       SortName  varchar(64),
       SortCount int
    ) 

    --创建临时表,保存数量最多的三级分类ID
    Create table #TemPThirdSortTable
    (
       ID        int identity(1,1),
       SortID    int unique,
       SortCount int,
       ParentSortID int,
       SortName  varchar(64)
    )

    --创建临时表,用来保存返回给用户的分类的名称
    Create table #TempReturnThirdSortTable
    (
       ID        int identity(1,1),
       SortName  varchar(64)
    )

/*
ashzs:
1、很不喜欢你这种不写明对应字段的做法,字段又不多,为什么不为#TempSecontSortTable写出插入的字段名?
2、如果是sql2005(包括200