如何在Sql Server上使用一条SQL查询结果总数并且分页

SELECT * FROM
(SELECT [ORDERID],ROW_NUMBER() OVER(ORDER BY ORDERID) RN,COUNT(*) OVER() AS TOTAL
  FROM [TSQLFUNDAMENTALS2008].[SALES].[ORDERS]
  ) T
  WHERE RN BETWEEN 1 AND 20

Total列返回的就是结果总数了。

通常,查询时会对结果进行分页,同时还要查询结果总数是多少。笔者刚接触编程时,到现在,都是这样做的,先把sql的结果count一下,再进行分页查询。

这样需要2次查询,而且同样的sql,数据库需要执行2次,浪费啊,能不能一次就出结果?

这样sql执行的笛卡尔积运算、过滤等等操作都可以省略一次,如果数据库缓存不能命中,还要访问硬盘io……程序访问数据库,还要再多一次网络io,这都是耗时的操作。

当然疑问也有,有必要这样做吗?效果如何?

我便测试了一下,预想性能提高一倍,但是我想错了,直接上结果,再上测试代码,测试的内容就是查询每个员工产生的订单金额。

2次查询方法耗时:62659107纳秒,63毫秒
1条Sql查询方法耗时:5389314纳秒,5毫秒

性能提高了10倍,当然这意义不大,但是这样的查询在软件中是最常见的,软件80%的时间都是在处理这样简单的事情,那么软件整体的性能都会有质的飞跃。

感兴趣的朋友也可以用ab在web上做一下压力测试。

下面上代码,数据库使用的是TSQLFundamentals2008,可以自行google,或者http://pan.baidu.com/s/1hqqmFfY,直接下载数据库sql。

using System;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;

namespace CountTest
{
    class Program
    {
        static string conStr = "Persist Security Info=False;Integrated Security=true;Initial Catalog=TSQLFundamentals2008;server=(local)";
        static long nanosecPerTick = (1000L * 1000L * 1000L) / Stopwatch.Frequency;

        static void Main(string[] args)
        {
            test1();

            test2();
        }

        static void test1()
        {
            var t1 = Stopwatch.StartNew();
            using (SqlConnection conn = new SqlConnection(conStr))
            {
                conn.Open();
                var comCount = new SqlCommand(@"select COUNT(*) from 
(select emp.empid,SUM(od.unitprice*od.qty) money
from HR.Employees emp
left join Sales.Orders o on o.empid = emp.empid
left join Sales.OrderDetails od on od.orderid = o.orderid
group by emp.empid
) t", conn);
                var count = comCount.ExecuteScalar();
                var pageCount = new SqlCommand(@"select empid,money from 
(select emp.empid,SUM(od.unitprice*od.qty) money,ROW_NUMBER() over(order by emp.empid) rm
from HR.Employees emp
left join Sales.Orders o on o.empid = emp.empid
left join Sales.OrderDetails od on od.orderid = o.orderid
group by emp.empid
) t where rm between 1 and 20", conn);
                var dataAdapter = new SqlDataAdapter(pageCount);
                dataAdapter.Fill(new DataTable());
            }
            t1.Stop();
            Console.WriteLine("test1方法耗时:{0}纳秒,{1}毫秒", t1.ElapsedTicks * nanosecPerTick, t1.ElapsedMilliseconds);
        }

        static void test2()
        {
            var t2 = Stopwatch.StartNew();
            using (SqlConnection conn = new SqlConnection(conStr))
            {
                conn.Open();

                var dTable = new DataTable();
                var pageCount = new SqlCommand(@"select empid,money,a from 
(select emp.empid,SUM(od.unitprice*od.qty) money,ROW_NUMBER() over(order by emp.empid) rm,COUNT(*) over() a
from HR.Employees emp
left join Sales.Orders o on o.empid = emp.empid
left join Sales.OrderDetails od on od.orderid = o.orderid
group by emp.empid
) t where rm between 1 and 20", conn);
                var dataAdapter = new SqlDataAdapter(pageCount);
                dataAdapter.Fill(dTable);
                var count = dTable.Rows.Count > 0 ? dTable.Rows[0].ItemArray[dTable.Rows[0].ItemArray.Length - 1] : 0;
                dTable.Columns.RemoveAt(dTable.Columns.Count - 1);
            }
            t2.Stop();
            Console.WriteLine("test2方法耗时:{0}纳秒,{1}毫秒", t2.ElapsedTicks * nanosecPerTick, t2.ElapsedMilliseconds);
        }
    }
}


你可能感兴趣的:(如何在Sql Server上使用一条SQL查询结果总数并且分页)