SQL多出limit ?导致报错

PgageHelper使用不当导致sql报错

1、发现接口调用异常

org.springframework.jdbc.BadSqlGrammarException: 
 select * from table where xx
 order by cl.plan_live_time asc         limit 20 LIMIT ?

发现出现了limit 语法错误 limit 20 LIMIT ?

2、排查 业务sql

 select * from table where xx
        order by cl.plan_live_time asc
        limit 20

查看业务sql没有问题,也不会存在拼接问题,怀疑组件帮忙做了添加limit ?这件事

3、发现 PageHelper使用不当会造成该问题

  PageHelper.startPage(pageInfoVO.getPage(), pageInfoVO.getPageSize());

底层会调用下面的方法:

public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        Page<E> oldPage = getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }

        setLocalPage(page);
        return page;
    }

调用setLocalPage(page);

public abstract class PageMethod {
    protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal();
    protected static boolean DEFAULT_COUNT = true;

    public PageMethod() {
    }

    protected static void setLocalPage(Page page) {
        LOCAL_PAGE.set(page);
    }

    public static <T> Page<T> getLocalPage() {
        return (Page)LOCAL_PAGE.get();
    }

    public static void clearPage() {
        LOCAL_PAGE.remove();
    }

Springbootinterceptor会拦截PageHelper做sql增强处理,如果PageHelper中含有Page分页参数,则会添加limit ?
1、setLocalPage后,变量和线程进行绑定,在上下文中环境中都可能存在PageHelper中设置的Page分页参数,后面的sql可能会添加limit ?。
2、ThreadLocal 中的ThreadLocalMap中的key是弱引用,发生GC时会被回收。如果其他请求分配到了此线程时未发生gc,则新请求也会出现此问题。

4、解决方式

在需要执行分页查询的sql前,开启PageHelper分页,执行完后清空PageHelper.clearPage()就是删除之之前在ThreadLocalMap中的Page

 PageHelper.startPage(pageDTO.getPage(), pageDTO.getPageSize());
 //分页sql代码
   ......
 //清理PageHelper可能自动添加limit导致分页bug
 PageHelper.clearPage();      
### ClickHouse MEMORY_LIMIT_EXCEEDED 报错的原因及解决方案 #### 原因分析 ClickHouse 中 `MEMORY_LIMIT_EXCEEDED` 错误通常发生在查询过程中使用的内存超过了设定的最大限制。默认情况下,ClickHouse 对单个查询的内存使用上限设置为 10 GiB[^1]。如果某个查询尝试分配超过此限制的内存,则会触发该错误。 这种问题可能由以下几个因素引起: 1. **大数据集处理**:当查询涉及大量数据(如扫描近200M行的数据),可能会消耗较多内存资源。 2. **复杂计算操作**:某些聚合函数(如 `uniqExact`)或复杂的 JOIN 和 GROUP BY 操作可能导致更高的内存需求。 3. **不合理的配置参数**:例如未调整 `max_memory_usage` 或其他相关参数,使得系统无法适应高负载场景下的内存需求。 --- #### 解决方案 ##### 方法一:增加最大允许内存限制 可以通过修改 ClickHouse 配置文件中的 `max_memory_usage` 参数来提升单次查询可使用的最大内存量。具体做法是在配置文件中添加或更改以下字段: ```xml <profiles> <default> <!-- 设置新的内存限制 --> <max_memory_usage>20000000000</max_memory_usage> <!-- 单位字节, 此处设为20GB --> </default> </profiles> ``` 或者通过 SQL 动态调整当前 session 的内存限制: ```sql SET max_memory_usage = '20Gi'; ``` 这种方法适用于临时需要更高内存支持的情况,但需谨慎评估硬件条件以防止 OOM (Out of Memory)。 ##### 方法二:优化查询逻辑 重新设计查询语句可以显著降低其对内存的需求。以下是几种常见的优化手段: - 替换耗内存较高的聚合函数;比如用更高效的近似算法代替精确去重(`uniqExact`)。 - 减少中间结果大小——利用过滤器提前排除不必要的记录。 对于大规模数据集合上的运算尤其重要的是考虑分步执行策略而不是一次性加载整个数据集到内存里完成所有工作流。 ##### 方法三:启用分布式模式或多节点部署 如果单一服务器难以满足高性能需求,那么构建集群环境将是另一个可行的选择。借助副本机制(replication),不仅可以提高可用性和容灾能力,还能分散读写压力从而缓解局部资源紧张状况[^2]。 另外,在多台机器上平行运行相同任务也可以有效分割原始问题规模进而减少个体负担。 ##### 方法四:合理应用采样技术 针对那些不需要绝对精准统计的应用场合来说,采用样本估算往往能带来事半功倍的效果。MergeTree引擎家族成员本身就具备良好的原生支持特性,只需定义好相应的抽样表达式即可开启这项功能[^3]。 最后值得注意的一点是网络层面超时控制同样不容忽视,适当延长连接等待时限有助于避免因为短暂延迟而导致失败中断现象发生[^4]。 --- ### 总结 综上所述,面对 ClickHouse 查询过程中可能出现的 `MEMORY_LIMIT_EXCEEDED` 异常情况,可以从多个角度出发寻找对应措施加以应对。无论是直接扩大物理容量边界还是深入挖掘业务特点寻求替代路径都值得探索实践一番。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值