分页代码及相应SQL效率的分析

 前阵子一直在研究一个老问题,就是分页效率问题。虽然网上代码不计其数,但是大部分都是雷同的,不尽如人意。在此我把这几天的研究成果给大家分享下,希望对各位程序开发人员有所帮助。(注:这里没有研究分页缓存机制的问题,只是从优化SQL语句考虑)。

在数据访问层中:

代码:


private const string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_IN = "SELECT TOP {0} * FROM (SELECT TOP {1} Id,Title,AddUser,CreateTime FROM [Messages] WHERE Id NOT IN (SELECT TOP {2} Id FROM [Messages])) as [Msg]";

/// <summary>

/// Get Single Page Message List,SQL的TOP,Not In方式

/// </summary>

/// <param name="pgpo">PaginationGoPageObject</param>

/// <returns>IList</returns>

public static IList GetSinglePageMessageListForSqlTopIn(PaginationGoPageObject pgpo)

{

DataBaseInstance dbInstance = new DataBaseInstance();

dbInstance.Open(1);

//不能通过参数的方式来实现

string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_IN_str = string.Format(GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_IN, pgpo.PageSize, pgpo.PageSize * pgpo.CurrentPage, pgpo.PageSize * (pgpo.CurrentPage - 1));

dbInstance.SqlCommandText = GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_IN_str;

IList MsgList = dbInstance.ExecuteList();

dbInstance.Close();

IList messageDataObjects;

if (MsgList == null || MsgList.Count == 0)

{

messageDataObjects = null;

}

else

{

messageDataObjects = new ArrayList(MsgList.Count);

foreach (IDictionary dicMessageDO in MsgList)

{

MessageDataObject messageDO = new MessageDataObject();

messageDO.Id = Convert.ToInt32(dicMessageDO["ID"]);

messageDO.Title = dicMessageDO["TITLE"].ToString();

messageDO.AddUser = dicMessageDO["ADDUSER"].ToString();

messageDO.CreateTime = (DateTime)dicMessageDO["CREATETIME"];

//messageDO.SortId = (int)dicMessageDO["SORTID"];

//messageDO.Message = dicMessageDO["MESSAGE"].ToString();

//messageDO.Reply = dicMessageDO["REPLY"].ToString();

//messageDO.Image = dicMessageDO["IMAGE"] as byte[];

messageDataObjects.Add(messageDO);

}

}

return messageDataObjects;

}


private const string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX = "SELECT TOP {0} Id,Title,AddUser,CreateTime FROM [Messages] WHERE (Id > (SELECT MAX(Id) FROM (SELECT TOP {1} Id FROM [Messages] ORDER BY Id) AS [Msg_temp]))";

<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script>

/// <summary>

/// Get Single Page Message List,SQL的TOP,MAX方式

/// </summary>

/// <param name="pgpo">PaginationGoPageObject</param>

/// <returns>IList</returns>

public static IList GetSinglePageMessageListForSqlTopMax(PaginationGoPageObject pgpo)

{

DataBaseInstance dbInstance = new DataBaseInstance();

dbInstance.Open(1);

//不能通过参数的方式来实现

string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX_str = null;

if (pgpo.CurrentPage == 1)//判断是否为首页

{

GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX_str = string.Format("SELECT TOP {0} Id,Title,AddUser,CreateTime FROM [Messages]", pgpo.PageSize);

}

else

{

GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX_str = string.Format(GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX, pgpo.PageSize, pgpo.PageSize * (pgpo.CurrentPage - 1));

}

dbInstance.SqlCommandText = GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_TOP_MAX_str;

IList MsgList = dbInstance.ExecuteList();

dbInstance.Close();

IList messageDataObjects;

if (MsgList == null || MsgList.Count == 0)

{

messageDataObjects = null;

}

else

{

messageDataObjects = new ArrayList(MsgList.Count);

foreach (IDictionary dicMessageDO in MsgList)

{

MessageDataObject messageDO = new MessageDataObject();

messageDO.Id = Convert.ToInt32(dicMessageDO["ID"]);

messageDO.Title = dicMessageDO["TITLE"].ToString();

messageDO.AddUser = dicMessageDO["ADDUSER"].ToString();

messageDO.CreateTime = (DateTime)dicMessageDO["CREATETIME"];

messageDataObjects.Add(messageDO);

}

}

return messageDataObjects;

}


private const string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_CURSOR = "SELECT TOP {0} Id,Title,AddUser,CreateTime FROM [Messages]";

/// <summary>

/// Get Message List For Single,游标方式

/// </summary>

/// <param name="pgpo">PaginationGoPageObject</param>

/// <returns>IList</returns>

public static IList GetSinglePageMessageListForSqlCursor(PaginationGoPageObject pgpo)

{

DataBaseInstance dbInstance = new DataBaseInstance();

dbInstance.Open(1);

//不能通过参数的方式来实现

string GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_CURSOR_str = string.Format(GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_CURSOR, pgpo.PageSize * pgpo.CurrentPage);

dbInstance.SqlCommandText = GET_SINGLE_PAGE_MESSAGE_LIST_FOR_SQL_CURSOR_str;

IList MsgList = dbInstance.ExecuteListForPage(pgpo.PageSize,pgpo.CurrentPage);

dbInstance.Close();

IList messageDataObjects;

if (MsgList == null || MsgList.Count == 0)

{

messageDataObjects = null;

}

else

{

messageDataObjects = new ArrayList(MsgList.Count);

foreach (IDictionary dicMessageDO in MsgList)

{

MessageDataObject messageDO = new MessageDataObject();

messageDO.Id = Convert.ToInt32(dicMessageDO["ID"]);

messageDO.Title = dicMessageDO["TITLE"].ToString();

messageDO.AddUser = dicMessageDO["ADDUSER"].ToString();

messageDO.CreateTime = (DateTime)dicMessageDO["CREATETIME"];

messageDataObjects.Add(messageDO);

}

}

return messageDataObjects;

}

 

以上用了SQL的3种方式:Not In方式,Max()方式,游标方式。

在我的电脑上DELL品牌机(型号:E520,内存增至2G,双核CPU),我导入了1000万条数据,每页显示10条记录。

以下是测试报告。

前面的分页显示时间

最后的分页显示时间

Not In方式

1秒内

6秒左右

Max()方式

1秒内

4-5秒

游标方式

1秒内

8秒左右


不难看出,Max()方式是效能最高的,它的缺点当然也很明显:增加了数据库服务器的负担。

Not In方式是不可取的,它不仅增加服务器负担,还是效率最低的。

当然对于我们来说,还要结合实际情况做合理的判断,进行取舍。

在无数次的试验中,我个人的经验就是好的算法是取得好效果的关键,在此我也望各位程序员对算法加强足够的重视,写出更优秀的代码。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: SQL优化是通过改进查询语句的性能来提高数据库系统的查询效率。基于Oracle数据库SQL优化源代码主要包括以下几个方面的内容: 1. 查询语句的编写与优化:合理编写SQL查询语句,避免使用不必要的表连接、子查询等复杂操作,使用WHERE子句过滤数据以减少返回结果集的大小,避免使用通配符查询,尽量使用索引字段进行查询。 2. 索引的优化与使用:根据查询频率与性能需求,为查询字段添加索引,避免全表扫描操作,提高查询速度。对于大表,可以考虑使用分区索引或位图索引来提高查询性能。 3. 数据库统计与分析:通过Oracle的统计信息,对表、索引、列等数据库对象进行分析,确定是否需要重新构建或刷新统计信息,以提供准确的优化器成本估算值,确保SQL查询的性能最佳。 4. 数据库参数调优:根据实际的系统负载情况,调整Oracle数据库的参数配置,包括内存分配、并发连接数、缓冲池大小、日志文件大小等,在不同的应用场景下,调优数据库参数可以提高SQL查询的性能。 5. SQL性能监控:通过Oracle提供的性能监控工具,如AWR报告、ASH报告等,分析SQL语句的执行计划、等待事件、锁等信息,找出性能瓶颈并进行相应的优化。 以上是基于Oracle的SQL优化源代码的主要内容,通过优化查询语句、使用索引、统计分析数据库参数调优和SQL性能监控等手段,可以提高SQL查询的性能,提升整个数据库系统的效率。 ### 回答2: 优化Oracle的SQL代码可以通过以下几个步骤实现。首先,可以通过使用合适的索引来优化查询性能。索引可以加查询速度,减少数据库访问的次数。但是要注意,过多的索引可能会降低数据更新性能,所以需要找到合适的平衡点。 其次,可以通过使用分区表来提高查询性能。分区表将数据按照特定的规则分割成多个分区,可以在查询时只访问特定的分区,提高查询效率。 另外,可以对SQL语句进行优化,比如避免使用不必要的表连接、避免使用子查询等。可以使用EXPLAIN PLAN工具来分析SQL语句的执行计划,从而找出潜在的性能瓶颈,并进行优化。 此外,还可以通过使用合适的并行处理来提高查询的性能。Oracle数据库支持并行执行,可以同时使用多个CPU来处理查询请求,从而加查询速度。 最后,还可以通过调整Oracle数据库的参数来优化性能。可以根据系统的实际情况,调整SGA和PGA内存大小,优化数据库缓存和排序操作的性能。 总之,基于Oracle的SQL优化源代码主要包括索引优化、分区表优化、SQL语句优化、并行处理和数据库参数调优。通过综合应用以上方法,可以显著提高数据库查询的性能和效率。 ### 回答3: Oracle的SQL性能优化是通过不断优化SQL查询语句和数据库结构来提升查询性能的过程。下面是一个基于Oracle的SQL优化的源代码示例: ```sql -- 创建索引来加查询性能 CREATE INDEX idx_customer_name ON customer (name); -- 选择适当的数据类型,减小存储空间 ALTER TABLE orders MODIFY (total_cost NUMBER(10, 2)); -- 使用内联视图来提高查询效率 SELECT o.order_id, o.order_date, od.product_name, od.quantity FROM orders o JOIN ( SELECT order_id, product_name, quantity FROM order_details WHERE quantity > 5 ) od ON o.order_id = od.order_id WHERE o.order_date BETWEEN TO_DATE('2022-01-01', 'YYYY-MM-DD') AND TO_DATE('2022-01-31', 'YYYY-MM-DD'); -- 查询结果分页 SELECT * FROM ( SELECT rownum AS rn, customer_id, name, address FROM customer ORDER BY name ) WHERE rn BETWEEN 11 AND 20; -- 使用分区表提高查询性能 CREATE TABLE sales ( sale_id NUMBER, sale_date DATE, product_id NUMBER, quantity NUMBER, amount NUMBER ) PARTITION BY RANGE (sale_date) ( PARTITION sales_q1 VALUES LESS THAN (TO_DATE('2022-04-01', 'YYYY-MM-DD')), PARTITION sales_q2 VALUES LESS THAN (TO_DATE('2022-07-01', 'YYYY-MM-DD')), PARTITION sales_q3 VALUES LESS THAN (TO_DATE('2022-10-01', 'YYYY-MM-DD')), PARTITION sales_q4 VALUES LESS THAN (TO_DATE('2023-01-01', 'YYYY-MM-DD')) ); ``` 以上是一些常用的基于Oracle的SQL优化源代码示例,通过索引创建、数据类型选择、内联视图、分页查询和分区表等方法,可以提高SQL查询的性能和效率。当然,具体优化的方式还需要根据实际情况进行调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值