编程技巧:SQL 处理超大查询
初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
源码指引:github源码指引_初级代码游戏的博客-CSDN博客
一、数据库对内存和执行时间的限制
处理数据库的时候很头疼的是数据库管理员很讨厌!非常讨厌!莫名其妙地,查询就失败了,连接就被复位了,怎么回事?因为数据库管理员干预了。
查询数据量太大?不可以!查询时间太长?不可以!他就管他的数据库不要垮,不管你需要什么、不管客户需要什么!
不过也要互相理解啊,大家都不容易,搞死了数据库大家都玩完。
二、分段查询(分页查询)
所以遇到超大查询时我们一般会分段执行,限制返回的数据量,这种技术在前端也被称为“分页查询”。(分页就分页吧,你默认返回10行是怎么想的?你的屏幕这么小?)
不吐槽前端了,我们做大业务处理的需要尽可能多返回数据,同时还要照顾数据库管理员的情绪,所以我们除了做分段还要耍点花招,毕竟分段太小会降低性能啊。
我们要一个复杂一点的策略:自动寻找最合适分段。
三、动态分段大小的例程
下面就是一个自动寻找最合适分段的例子,策略也不复杂:先从一个足够巨大的limit(mysql是limit,别的数据库应该不一样,比如oracle是rownum)开始,如果执行失败就减半,直到成功。
代码如下(C#的,不过原理都是相同的):
Int32 last_id = Int32.MinValue;
int limit = 100 * 10000;
int total_records = 0;
while (true)
{
StringBuilder sql = new StringBuilder();
sql.Append($"select id,其它列 from 表 where id>{last_id} order by id limit {limit} ");
MySqlCommand cmd = new MySqlCommand(sql.ToString(), mySqlTools.connection);
MySqlDataReader reader = cmd.ExecuteReader();
int current_count = 0;
try
{
while (reader.Read())
{
if (total_records < 10)
{
ListViewItem item = listView_1.Items.Add(reader[0].ToString());
item.SubItems.Add(reader[1].ToString());
item.SubItems.Add(reader[2].ToString());
item.SubItems.Add(reader[3].ToString());
}
last_id = reader.GetInt32(0);
++current_count;
++total_records;
}
reader.Close();
}
catch (Exception ex)
{
MessageBox.Show($"limit {limit},将减半 已获取数据{total_records}条", "limit");
limit /= 2;
}
if (0 == current_count) break;
}
MessageBox.Show($"记录 {total_records} 最终limit {limit}", "总数");
我这个代码原来不用分段就行,后来数据量太大了,超过30秒就被断开连接了。
查询按照id顺序,因此记住上一个id就可以继续查询。
(这里是文档结束)