1、优化SQL语句,使用Where限定查询的数据范围
2、建立相关字段的索引,避免查询时进行全表扫描
3、多数据表连接时,注意连接的主从表位置,避免小表Join大表
② sql数据库 大数据量查询 优化!!
我搞过一个销售管理的网站,一些客户的浏览记录也很多.
后来我们用了按类型分表的方法.把一个很长的表分成了7个表,然后建立视图来把他们弄一起,当然SQL优化是少不了的,尽量减少join和left的次数,适当建立索引.
你朋友圈的话,建议你用Ajax,动态刷新,那么是否考虑在这一次刷新页面的时候在后台先准备好下一次的查询数据呢.因为这个是一段一段的,显示一段,然后准备下一段.
PS:我这只是个人建议,希望能帮到你
③ 大数据量实时统计排序分页查询 优化总结
大数据量实时统计排序分页查询 (并发数较小时) 的瓶颈不是函数(count,sum等)执行,
不是having, 也不是order by,甚至不是表join, 导致慢的原因就在于“数据量太大本身”
就是将表划分为M份相互独立的部分,可以是分表,也可以是不分表但冗余一个取模结果字段
实际结果是不分表比分表更加灵活,只需稍加配置,就可以动态切分大表,随意更改M的大小。
将1条慢sql(大于30秒)拆分成为N条查询速度巨快的sql(单条sql执行时间控制在20毫秒以内)
然后再web应用中以适当的线程数去并发查询这些执行时间快的N条小sql再汇总结果
第一步查询中去并发执行这N条小sql, 只取排序字段和标识字段,其他字段一律丢弃
汇总结果后定位出当前页面要显示的pageNum条数据,再进行第二步查询,取出页面上需要展示的所有字段
PS:这一点是至关重要的,其他几点都可以不看,这点是最关键的。慢慢解释一下:
a) 第一种方式是把数据库中所有记录(只取排序字段和标识字段并且不做任何sum,count having order by等操作)
全部拉到web应用中,在web应用中完成所有的计算
b) 第二种方式是把数据库中所有记录做sum count having等操作之后的所有行数拉到web应用中,在web应用中完成剩余计算
c) 第三种方式是把数据库中所有记录做sum count having order by等操作之后把limit后的数据拉到web应用中,
在web应用中对limit后的数据再计算
显然,第一种方式 数据库什么活都不做只取数据 是不可行的。以lg_order_count_seller为例,1500万行,
如果只算id, seller_id和order_count 这三个bigint类型,至少需要拉8*3*1500 0000 = 360000000=340M,
拉到内存中之后存储需要8*4*15000000= 460M,这还不算List是的2的n次方这个特点和计算排序等的内存开销,
不仅数据库与web应用机器IO扛不住,就是应用自身恐怕也要OOM了。
第二种方式,所有记录做sum count having等操作之后,由于是group by seller_id的,总得数据量变为100万(就是卖家总数),
这样子一来,共需要拉8*3*100 0000 = 23M,拉到内存之后,需要8*4*100 0000 = 30M, 再算上List是的2的n次方这个特点和
计算排序等的内存开销也不会超过100M, IO的时间和内存开销勉强可以考虑接受。
第三种方式,所有记录做sum count having order by等操作之后把limit后的数据拉到web应用中,因为做了limit,所以,
数据量很小了,无论是IO还是内存开销都已经很小了。可以忽略。
综合以上三种,第三种方式适用于页面的前n页和后n页,因为这个limit的数据量随着页数的增大而增大,
当大到每个切分后的小表的数据量时就转为第二种方式了。
第二种方式适用于页面的第[n+1, totaoPageNum-n]页。
切分成N条小sql后并行执行时排序不稳定性的解决办法
① 问题描述:
优化之前,还是是一条大慢sql查询时,由于数据库排序是稳定排序,
所以当两条记录排序字段值相同时他们在页面上的页码位置是固定的。
优化之后,当并行执行这N条小sql时,由于无法控制这些小sql的先后执行顺序,
导致在web应用中当两条记录的排序字段值相同时在页面上的页码位置是随机的。
② 解决办法:
除了拉标识字段(seller_id)和排序字段(order_count_sum)之外,再取一个unique(id)的字段,当两条记录的排序字段值相同时,再用这个unique的字段(在卖家监控中这个字段是id)进行第二次排序.这样就解决了排序不稳定的问题。
③ 也许,看到这里会有疑问,为什么不用seller_id?seller_id也是唯一, 这样子不是少取id这个字段,减少IO了?
seller_id虽然也是唯一,可以辅助排序,但是不要忘记数据库的排序规则是:
如果两列的值相等,那么序号在前的排在前面,这里的序号就是主键(自动生成,autoincrement),
如果用seller_id的话还是不能保证排序的稳定性,只能用主键id.
优先加载页面上的主要元素,然后再去异步加载次要元素,
反应在卖家监控页面中,查数据和查页页码的sql语句基本相同,是在竞争同一资源,
所以,需要做一个策略,优先把资源让给查数,数据查完之后再去查页码。
限流
由于多线程取数据并没有从本质上提高数据库性能,所以必须针对大数据量实时统计排序分页查询做限流
我这里打个比方:食堂有6个窗口,物流团队吃饭要买6个菜,平均每买1个菜需要1分钟的时间,
如果派我一个人去一个窗口买的话需要6分钟的时间
假如派6个人分别去6个窗口买这6个菜,只需要1分钟的时间
但是,如果除了物流团队,再来其他5个团队呢,也就是说6个团队每个团队买6个菜共买36个菜,
这样子有的团队先买完,有的团队后买完,但平均时间还是6分钟。本质上没有变化。
所以,对于特定的查询条件,必须进行限流。让每分钟至多有6个团队买菜,这样子能使得情况变得不至于太糟糕。
从根本上改变现状
这一点从目前来看只能是展望了,比如mysql数据库换更为强大的oracle数据库,
或更换InnoDb引擎为其他,或更换SATA硬盘为SSD 。。。。。。
从实践效果来看,优化后的效果是很明显的。
相同的查询条件,原来一个页面查询时间由于超过60秒超时了,根据1-6点建议优化之后,查询时间变为2秒至3.5秒之间。
④ (问题解决再追加100分)sql server存储过程实现查询数据条数过大,分页查询怎么实现
按说5-8w这样数量级的数据没有问题,写入Excel是布比较耗性能,主要还是要通过优化写入Excel的代码效率上去考虑。你可以考虑利用分批查询写入的方式来避免一次写太多的数据到Excel:将你的查询结果分段,比方你的语句中能不能用时间来认为分段,每次返回部分结果。
回到你的问题,对大数据量查询的解决方案有以下两种:
(1)、将全部数据先查询到内存中,然后在内存中进行分页,这种方式对内存占用较大,必须限制一次查询的数据量。
(2)、采用存储过程在数据库中进行分页,这种方式对数据库的依赖较大,不同的数据库实现机制不通,并且查询效率不够理想。以上两种方式对用户来说都不够友好。
2.解决思路
通过在待查询的数据库表上增加一个用于查询的自增长字段,然后采用该字段进行分页查询,可以很好地解决这个问题。下面举例说明这种分页查询方案。
(1)、在待查询的表格上增加一个long型的自增长列,取名为“queryId”,mssql、sybase直接支持自增长字段,oracle可以用sequence和trigger来实现。然后在该列上加上一个索引。
添加queryId列的语句如下:
Mssql: [QUERYID] [bigint] IDENTITY (1, 1)
Sybase: QUERYID numeric(19) identity
Oracle:
CREATE SEQUENCE queryId_S
INCREMENT BY 1
START WITH 1
MAXVALUE 999999999999999 MINVALUE 1
CYCLE
CACHE 20
ORDER;
CREATE OR REPLACE TRIGGER queryId_T BEFORE INSERT
ON "test_table"
FOR EACH ROW
BEGIN
select queryId_S.nextval into :new.queryId from al;
END;
(2)、在查询第一页时,先按照大小顺序的倒序查出所有的queryId,
语句如下:select queryId from test_table where + 查询条件 +order by queryId desc 。
因为只是查询queryId字段,即使表格中的数据量很大,该查询也会很快得到结果。然后将得到的queryId保存在应用服务器的一个数组中。
(3)、用户在客户端进行翻页操作时,客户端将待查询的页号作为参数传递给应用服务器,服务器通过页号和queyId数组算出待查询的queyId最大和最小值,然后进行查询。
算出queyId最大和最小值的算法如下,其中page为待查询的页号,pageSize为每页的大小,queryIds为第二步生成的queryId数组:
int startRow = (page - 1) * pageSize
int endRow = page * pageSize - 1;
if (endRow >=queryIds.length)
{
endRow = this.queryIds.length - 1;
}
long startId =queryIds[startRow];
long endId =queryIds[endRow];
查询语句如下:
String sql = "select * from test_table" + 查询条件 + "(queryId <= " + startId + " and queryId >= " + endId + ")";
3.效果评价
该分页查询方法对所有数据库都适用,对应用服务器、数据库服务器、查询客户端的cpu和内存占用都较低,查询速度较快,是一个较为理想的分页查询实现方案。经过测试,查询4百万条数据,可以在3分钟内显示出首页数据,以后每一次翻页操作基本在2秒以内。内存和cpu占用无明显增长。
以上也仅仅是分页查询结果查看的问题,你需要写入到Excel的话还需要考虑Excel写入代码的执行效率,这部分是很值得研究的。
⑤ 如何优化Sql server 大数据量时使用 like 查询的速度或有什么别的方法实现模糊查询
傻逼啊,谁看了这个文章就是误人子弟 方案1:主键Id,默认为聚集索引,不建立其它非聚集索引select * from News where Title like '%"&abigale&"%' or Author like '%"&abigale&"%' order by Id desc从字段Title和Author中模糊检索,按Id排序查询时间:50秒方案2:主键Id,默认为聚集索引在Title、Author、Star上建立非聚集索引select * from News where Title like '"&abigale&"%' or Author like '"&abigale&"%' order by Id desc从字段Title和Author中模糊检索,按Id排序查询时间:2 - 2.5秒 看到没有,那个50秒用的是 '%"&abigale&"%'来的,两个百分号会引发全表扫描而那个快的是 '"&abigale&"%' ,这样就使用索引 不用索引和用索引完全两个概念,尼玛还在说优化,优化你妹
⑥ 数据量大,维度多怎么sql做查询,
1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引。
2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:
select id from t where num=0
3.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。
4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:
select id from t where num=10 or num=20
可以这样查询:
select id from t where num=10
union all
select id from t where num=20
5.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from t where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
6.下面的查询也将导致全表扫描:
select id from t where name like '%abc%'
若要提高效率,可以考虑全文检索。
7.如果在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:
select id from t where num=@num
可以改为强制查询使用索引:
select id from t with(index(索引名)) where num=@num
8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where num/2=100
应改为:
select id from t where num=100*2
9.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:
select id from t where substring(name,1,3)='abc'--name以abc开头的id
select id from t where datediff(day,createdate,'2005-11-30')=0--‘2005-11-30’生成的id
应改为:
select id from t where name like 'abc%'
select id from t where createdate>='2005-11-30' and createdate<'2005-12-1'
10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。
11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。
12.不要写一些没有意义的查询,如需要生成一个空表结构:
select col1,col2 into #t from t where 1=0
这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:
create table #t(...)
13.很多时候用 exists 代替 in 是一个好的选择:
select num from a where num in(select num from b)
用下面的语句替换:
select num from a where exists(select 1 from b where num=a.num)
14.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用。
15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了 insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过6个,若太多则应考虑一些不常使用到的列上建的索引是否有必要。
16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否应将该索引建为 clustered 索引。
17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字符串中每一个字符,而对于数字型而言只需要比较一次就够了。
18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要高些。
19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回用不到的任何字段。
20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。
21.避免频繁创建和删除临时表,以减少系统表资源的消耗。
22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。
23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。
24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。
25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过1万行,那么就应该考虑改写。
26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,基于集的方法通常更有效。
27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。
28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。
29.尽量避免大事务操作,提高系统并发能力。
30.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。
⑦ SQL查询数据量太大的该怎么解决
那要看你sql怎么写 如果是select * 那当然有问题了 如果是select count(*) 就没事 当然你得给你的数据库加索引 如果你的记录能确认都不被删除 可以select max(id)
⑧ SQL查询大量数据问题
1. 对检索的条件项建索引
2. 将数据按照时间分区或者分表存储。
3. 将历史的不需要的数据导出后者存储到其他磁盘。