问题反馈:PostgreSQL分页异步查询分区表当查询结果大于1.5W行时前N页加载很慢 返回

SqlSugar 沟通中
20 1045

SqlSugar版本:SqlSugarCore 5.1.3.30

数据库:PostgreSQL 9

C# .net6 web站点


问题描述:这是一个很神奇的现象,每天新增的记录数大约在(2-3万行之间),直接执行SQL无延时卡顿现象,分页异步查询分区表当查询结果大于1.5W行时前N页加载很慢,且分2种情况


  1、默认查询当天数据,当查询结果行数不多时响应时间正常,大于1.5万行时开始第1页卡,数量越多从第1页起卡的页数越多,如:超过2万行时,前5页卡,页码大于5就不卡了。

  2、改变条件查今天之前的历史数据时(查一天的),第一次打开页面时至少卡10秒以上,数据加载完成后,再次刷新或翻页响应效率为第1种情况。


PostgreSQL分区表,结构如下

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE IF NOT EXISTS x_record
(
    id serial8 NOT NULL,
    add_time timestamptz,
    --此处省略6个integer,1个varcahr,13个bigint,1个timestamptz
) PARTITION BY RANGE (add_time);
 
CREATE TABLE x_record_202308 PARTITION OF x_record FOR VALUES FROM ('2023-08-01 00:00:00+08'TO ('2023-09-01 00:00:00+08');
 
CREATE INDEX IF NOT EXISTS x_record_202308_idx_add_time ON x_record_202308(add_time);
CREATE  INDEX  IF  NOT  EXISTS  x_record_202308_idx_id  ON  x_record_202308(id);

以下为C#查询代码,查询时间范围1天,每页20行

1
2
3
4
5
6
7
8
9
10
11
12
13
var exp = Expressionable.Create<x_record>()
    .And(a => SqlFunc.Between(a.add_time, fromTime, toTime))
    .ToExpression();
 
var list = await db.Queryable<x_record>()
    .Where(eWhere)
    .OrderBy(a => a.id, OrderByType.Desc)
    .Select(a => new x_view()
    {
        id = a.id ,
        add_time = a.add_time,
        //省略部分字段
    }).ToPageListAsync(page, 20);


解决方法:改用直接执行SQL再绑定就很丝滑了

1
2
3
4
5
6
7
8
9
10
11
string tmpSql = db.Queryable<x_record>()
    .Where(eWhere)
    .OrderBy(a => a.id, OrderByType.Desc)
    .Select(a => new x_view()
    {
        id = a.id ,
        add_time = a.add_time,
        //省略部分字段
    }).ToSqlString();
 
var list = await db.Ado.SqlQueryAsync<x_view>(tmpSql + $"limit 20 offset {((page - 1) * 20)};");


热忱回答20

  • -

    0 回复
  • -

    0 回复
  • 你都分页了怎么会慢呢?

    0 回复
  • 你看看是不是条件引起的

    0 回复
  • 这个速度应该是sql快慢,ToListAsync底层就是 db.Ado.SqlQueryAsync

    0 回复
  •  db.Queryable<Order>().Skip(1).Take(200).ToSqlString()

    比较一下SQL

    0 回复
  • @fate sta:对比了一下,SQL语句结构是一样的


    之所以说诡异是指分页时在前N页会卡顿,结果越多,N值会变大,超过页码分界线往后效率就正常了

    0 回复
  • @fate sta:刚才我重新写了查询案例:2种写法的效率是不一样的

    1、前N页卡顿的写法

    1
    db.xxxx.ToPageListAsync(page, limit);

    查询20页时间:

    total:16433,page:1,耗时:2309.9048

    total:16433,page:2,耗时:1553.7535

    total:16433,page:3,耗时:1581.5697

    total:16433,page:4,耗时:1549.5327

    total:16433,page:5,耗时:1652.3516

    total:16433,page:6,耗时:1614.657

    total:16433,page:7,耗时:1571.5268

    total:16433,page:8,耗时:1686.1091

    total:16433,page:9,耗时:1768.5345

    total:16433,page:10,耗时:1660.1226

    total:16433,page:11,耗时:1740.2945

    total:16433,page:12,耗时:1710.5694

    total:16433,page:13,耗时:1779.3872

    total:16433,page:14,耗时:1822.8966

    total:16433,page:15,耗时:1641.3461

    total:16433,page:16,耗时:1554.6926

    total:16433,page:17,耗时:1823.3728

    total:16433,page:18,耗时:79.5095

    total:16433,page:19,耗时:71.8547

    total:16433,page:20,耗时:59.9317


    2、以下写法效率正常

    1
    db.xxxxx.Skip((page - 1) * limit).Take(limit).ToListAsync();

    查询20页时间:

    total:16433,page:1,耗时:585.4071

    total:16433,page:2,耗时:67.9149

    total:16433,page:3,耗时:64.731

    total:16433,page:4,耗时:72.2917

    total:16433,page:5,耗时:110.8405

    total:16433,page:6,耗时:78.7364

    total:16433,page:7,耗时:88.1795

    total:16433,page:8,耗时:92.128

    total:16433,page:9,耗时:97.117

    total:16433,page:10,耗时:99.5275

    total:16433,page:11,耗时:105.6536

    total:16433,page:12,耗时:130.1762

    total:16433,page:13,耗时:129.8083

    total:16433,page:14,耗时:214.9252

    total:16433,page:15,耗时:183.8991

    total:16433,page:16,耗时:108.8862

    total:16433,page:17,耗时:100.3811

    total:16433,page:18,耗时:253.7756

    total:16433,page:19,耗时:166.4153

    total:16433,page:20,耗时:177.1487


    0 回复
  • 升级到:5.1.4.95版问题依然存在

    0 回复
  • 你是不是有查询count, Count会影响性能的

    0 回复
  • 如果还有问题 按模版提供DEMO

    https://www.donet5.com/Home/Doc?typeId=2366

    0 回复
  • db.xxxxx.Skip((page - 1) * limit).Take(limit).ToListAsync();

    在不查Count情况下等于

    ToPageLis 底层是一模一样的没有任何差异的地方


     

    0 回复
  • 数据量过大不要查询Count这个比较慢

    0 回复
  • @fate sta:剔除Count效率一样的不行,确定是ToPageList这个用法导致的效率问题,是否返回count问题都在,同步异步都有的,刚才还试了普通表,也有一样的情况。

    可能跟字段数量多少也有关系,同样的表结构复制4个字段没复现,有时间我整理复现列子


    0 回复
  • 不好意思最近有点忙,就没做案例,并且无意间找到为啥直接执行SQL不卡的原因了,分区表查询的时候,《分区键》作为查询条件时使用传参方式查询时无法触发《分区约束排除》导致查询所有子表导致效率极低,而直接使用SQL不会有这个问题

    0 回复
  • fate sta fate sta VIP0
    2023/9/19

    @道念迹奇:参数方式如果dbtype都一样也无触发是吗?

    0 回复
  • fate sta fate sta VIP0
    2023/9/19

    如果这样那就不是sqlsugar的问题了

    0 回复
  • fate sta fate sta VIP0
    2023/9/19

    dbtype不一样引起的慢可以看一下 文档:字符索引优化

    0 回复
  • @fate sta:对的不是sqlsugar的问题

    0 回复
  • @fate sta:不是索引问题,是PG分区表有个《分区约束排除》机制没触发导致的,《分区键》只能用具体值查询时才能触发定位对应子表,用内置函数、参数都无法触发

    0 回复
字号
代码语言
段落格式
字体
元素路径:
字数统计