zoukankan      html  css  js  c++  java
  • 人生苦短,必须性感。看看桃花,再聊聊技术

    嘿嘿,我又开始写博客了。

    其实也就是随便写写咯。2013刚刚开始,有运气好的时候,也有运气坏的时候。之所以说运气好是因为过年和朋友打麻将,基本上就看到我一个人胡咯,各种好牌,自摸的都不好意思了。其实我技术真的不行的,但似乎像我这种愣头青一般都是无心插柳成荫喔。然后运气坏的时候也是霉的不行。上上周和群里的朋友骑车翻越龙泉到樱桃沟看樱花的时候,不慎冲出了下坡变道,请假在家疗养了一周嘛。记得当时整个人就瘫在那儿了,大口大口的喘气,感觉到脸上在不断地往外面淌血,车车也不晓得摔得哪儿去了。还好在后面的车友跟了上来,几个妹子细心地蘸着开水擦我脸上的血,甚至还有人看我呼吸不过来的样子说要给我做人工呼吸。也许是这句吓到我了,我两扭两扭竟然站起来了!甩甩手啊脚的,发现没有什么问题,兜兜里面的手机也还是好的,身上沾了好多草灰,脸上虽然有几个口子但也不是很疼。然后,有骑友说叫车直接拉我回家,我一看我的车还是好的,就坚持着继续上路咯。后来在龙泉大伙还一起吃了个饭,回家都晚上11点了。一照镜子,其实也没有想像中的那么严重嘛。

    现在想起来,其实摔车的那次运气也不算太坏的。摔出去的那个坡也不是很陡。同行的都是朝气蓬勃,热心互助的车友。最严重的伤口也在太阳穴和眼睛之间。也没有断手断脚之类的。车车也没有摔坏。看来是我摔的有技巧哟。话说龙泉的桃花开了,这周再骑过去转转。

    再说说工作上的事吧。听说这周星期天要加班,但我感觉没什么事情啊。然后中午问同事加班做什么,同事说加班拿加班工资噻,我晕哦。今天就是改了网管系统的一些BUG。而且发现有一些数据量比较大的页面点分页的时候响应那个慢啊!奇怪的是客户都没有反映么。于是我就到代码库里面去找啊找。找到了下面的分页方法:

    View Code
      1         /// <summary>
      2         /// 运行分页查询
      3         /// </summary>
      4         /// <param name="tableName">查询数据表或视图名</param>
      5         /// <param name="indexName">索引字段名</param>
      6         /// <param name="indexDbType">索引字段类型</param>
      7         /// <param name="columns">返回字段列表</param>
      8         /// <param name="selection">查询条件</param>
      9         /// <param name="orderBy">排序方式</param>
     10         /// <param name="pageIndex">页面开始索引</param>
     11         /// <param name="pageSize">分页大小</param>
     12         /// <param name="buildObj">IDataReader 处理委托</param>
     13         /// <returns></returns>
     14         public RecordSet<T> ExecutePaging<T>(string tableName, string indexName, SqlDbType indexDbType, string[] columns, string selection, string orderBy,
     15             int pageIndex, int pageSize, DataReaderParserHandler<T> buildObj)
     16         {
     17             if (pageIndex < 0)
     18             {
     19                 pageIndex = 0;
     20             }
     21 
     22             if (pageSize == 0)
     23             {
     24                 return new RecordSet<T>();
     25             }
     26 
     27             StringBuilder commandText = new StringBuilder();
     28             commandText.AppendFormat(@"
     29 DECLARE @PageLowerBound int
     30 DECLARE @PageUpperBound int
     31 
     32 SET @PageLowerBound = @PageSize * @PageIndex
     33 SET @PageUpperBound = @PageLowerBound + @PageSize + 1
     34 
     35 CREATE TABLE #PageIndexForUsers 
     36 (
     37     IndexID int IDENTITY (1, 1) NOT NULL,
     38     {0} {1}
     39 )", indexName, indexDbType == SqlDbType.Int ? "int" : "bigint");
     40 
     41             commandText.AppendFormat(@"
     42 
     43 INSERT INTO 
     44     #PageIndexForUsers ({1})
     45 SELECT
     46     [{1}]
     47 FROM
     48     {0}", tableName, indexName);
     49 
     50             if (!string.IsNullOrEmpty(selection))
     51             {
     52                 commandText.AppendFormat(@"
     53 WHERE
     54     {0}", selection);
     55             }
     56 
     57             if (!string.IsNullOrEmpty(orderBy))
     58             {
     59                 commandText.AppendFormat(@"
     60 ORDER BY
     61     {0}", orderBy);
     62             }
     63 
     64             commandText.AppendFormat(@"
     65 
     66 SELECT
     67     {0}
     68 FROM
     69     [{1}]
     70 WHERE 
     71     [{2}] IN
     72         (
     73             SELECT
     74                 [{2}]
     75             FROM
     76                 #PageIndexForUsers 
     77             WHERE
     78                 [IndexID] > @PageLowerBound AND [IndexID] < @PageUpperBound
     79         )
     80 ", columns.Length == 0 ? "*" : string.Join(",", columns), tableName, indexName);
     81             commandText.AppendFormat(@"
     82 
     83 SELECT count(*) FROM #PageIndexForUsers
     84 
     85 DROP TABLE #PageIndexForUsers ");
     86 
     87             SqlCommand cmd = new SqlCommand();
     88             cmd.CommandText = commandText.ToString();
     89             cmd.Parameters.Add("@PageIndex", SqlDbType.Int).Value = pageIndex;
     90             cmd.Parameters.Add("@PageSize", SqlDbType.Int).Value = pageSize;
     91 
     92             RecordSet<T> sets = new RecordSet<T>();
     93             sets.PageIndex = pageIndex;
     94             sets.PageSize = pageSize;
     95 
     96             using (IDataReader dr = this.ExecuteReader(cmd))
     97             {
     98                 while (dr.Read())
     99                 {
    100                     sets.Add(buildObj(dr));
    101                 }
    102 
    103                 if (dr.NextResult()
    104                     && dr.Read())
    105                 {
    106                     sets.TotalRecords = (int)dr[0];
    107                 }
    108                 dr.Close();
    109             }
    110 
    111             return sets;
    112         }

    上面的代码就是利用临时表进行分页咯。事实证明,这个在大数量分页的时候似乎效率并不是很高啊。
    话说SqlServer不是在很久之前就引进了“表变量”嘛,分页的话效率肯定比临时表高不少。而且,也不知道为什么当初没有写一个通用的分页存储过程。呐,大牛的心思你真的不懂。

    其实很多朋友,包含之前我在做一些东西需要用到分页的时候,都是利用下面的SQL哦:

    SELECT TOP PageSize *
    FROM TableName
    WHERE ID NOT IN
            (SELECT TOP PageSize*(PageIndex-1) id  FROM TableName ORDER BY id)
    ORDER BY ID

    原理一看便知。Top语句的效率很高,通常情况下ID也是一个表的聚簇索引。但 not in 的效率就不敢恭维咯,即使换作 not exists 语句,也不会有太大的改观吧。

    记得很久以前看到一篇.NET的面试题集,有一道写Sql的,题干大概是这样的:

    “在SQLServer数据库,取出一个表A中第21到第30条记录,其中,ID为自动增长的主键, 但可能不是连续的”。

    有朋友就给出了两种解法:

    解1:select top 10 * from A where id not in (select top 20 id from A) 
    解2: select top 10 * from A where id > (select max(id) from (select top 20 id from A )as T)

    解1不必多说,解2利用max函数提取出id的最大值,以此为参照物进行分页,同时去掉了 not in 语句。思路当然比第一种高明咯。

    解2的分页原型如下:

    select top PageSize * from TableName
    where id>
          (select max (id) from
            (select top PageSize*(PageIndex-1) id from TableName order by id) as T
           )    
      order by id

    改造成存储过程基本就是下面这个样子:

    CREATE PROCEDURE P_DataPagination
                    @tblName      VARCHAR(255),        -- 查询的表名
                    @returnFields VARCHAR(1000) = '*', -- 需要返回的数据列
                    @sortField      VARCHAR(255) = '', -- 排序的字段名
                    @sortType    BIT = 0,              -- 设置排序类型, 非 0 值则降序
                    @pageSize     INT = 10,            -- 页尺寸
                    @pageIndex    INT = 1,             -- 页码
                    @totalCount      BIT = 0,          -- 返回记录总数, 非 0 值则返回
                    @strWhere     VARCHAR(1500) = ''   -- 查询条件 (注意: 不要加 where)                                           
    AS
      DECLARE  @strSQL VARCHAR(5000)  -- 主语句
      DECLARE  @strTmp VARCHAR(110)   -- 临时变量
      DECLARE  @strOrder VARCHAR(400) -- 排序语句
      IF @totalCount != 0             --如果@totalCount传递过来的不是0,就执行总数统计。
        BEGIN
          SET @strSQL = 'select count(*) as TotalCount from [' + @tblName + ']'
          IF @strWhere != ''
          begin
            SET @strSQL = @strSQL + ' where ' + @strWhere
          end
        END
        
      ELSE
        BEGIN
          IF @sortType != 0
            BEGIN
              SET @strTmp = '<(select min'
              SET @strOrder = ' order by [' + @sortField + '] desc'
            END
           ELSE
            BEGIN
              SET @strTmp = '>(select max'
              SET @strOrder = ' order by [' + @sortField + '] asc'
            END
          IF @pageIndex = 1
            BEGIN
              Set @strSql = 'select top ' + Str(@pageSize) + ' ' + @returnFields + '  from [' + @tblName + '] '
              IF @strWhere != ''
              begin
                SET @strSQL = @strSql + ' where ' + @strWhere 
              end
              SET @strSql = @strSql + ' ' + @strOrder        
            END
           ELSE
            BEGIN
              SET @strSQL = 'select top ' + Str(@pageSize) + ' ' + @returnFields + '  from [' + @tblName + '] where [' + @sortField + ']' + @strTmp + '([' + @sortField + ']) from (select top ' + Str((@pageIndex - 1) * @pageSize) + ' [' + @sortField + '] from [' + @tblName + ']' + @strOrder + ') as tblTmp)' + @strOrder
              IF @strWhere != ''
              begin
                SET @strSQL = 'select top ' + Str(@pageSize) + ' ' + @returnFields + '  from [' + @tblName + '] where [' + @sortField + ']' + @strTmp + '([' + @sortField + ']) from (select top ' + Str((@pageIndex - 1) * @pageSize) + ' [' + @sortField + '] from [' + @tblName + '] where ' + @strWhere + ' ' + @strOrder + ') as tblTmp) and ' + @strWhere + ' ' + @strOrder
              end
            END
        END
      EXEC(@strSQL)
    GO

    经过我的测试,上面这个分页存储过程性能确实比较稳定哦,而且在分页数据量明显增大的情况下,也有非常高效的表现。

    下面是我的测试代码:

    declare @startTime datetime ;
    set @startTime=getdate();
    
    exec P_DataPagination 
        @totalCount = 0,
        @tblName = 'targetsPort',
        @returnFields = 'id,portDesc,createTime,IfIndex,ifSpeed,IfName',
        @sortField = 'id',
        @pageSize = 2000,
        @pageIndex = 2,
        @sortType=0,
        
        @strWhere = ' portDesc like ''1%'' '
        
    select [耗费时间(ms)]=datediff(ms,@startTime,getdate()) 

    基本上也该收尾咯。虽然说咱家的防御值比较高,但路过的各位大神吐槽不要太猛烈哈。└(^o^)┘

  • 相关阅读:
    巴洛克式和哥特式的区别
    推荐阅读书籍,是时候再行动起来了。
    AtCoder ABC 159F Knapsack for All Segments
    AtCoder ABC 159E Dividing Chocolate
    AtCoder ABC 158F Removing Robots
    AtCoder ABC 158E Divisible Substring
    AtCoder ABC 157F Yakiniku Optimization Problem
    AtCoder ABC 157E Simple String Queries
    AtCoder ABC 157D Friend Suggestions
    AtCoder ABC 156F Modularness
  • 原文地址:https://www.cnblogs.com/mcmurphy/p/2959060.html
Copyright © 2011-2022 走看看