Junjie
4 天以前 3e793a6d2173889f4d006f2c8174f3eec4992745
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package com.core.config;
 
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
 
/**
 * Optimized pagination interceptor that avoids full-table COUNT queries
 * for pages without WHERE conditions.
 *
 * <p>Strategy:
 * <ul>
 *   <li>SQL WITH WHERE clause -> delegate to parent (normal COUNT(*), indexes help)</li>
 *   <li>SQL WITHOUT WHERE clause -> rewrite to simple SELECT COUNT(*) FROM table,
 *       which lets InnoDB choose the smallest available index for the scan</li>
 * </ul>
 */
@Slf4j
public class FastPaginationInnerInterceptor extends PaginationInnerInterceptor {
 
    public FastPaginationInnerInterceptor(DbType dbType) {
        super(dbType);
    }
 
    @Override
    public String autoCountSql(IPage<?> page, String sql) {
        if (!page.optimizeCountSql()) {
            return super.autoCountSql(page, sql);
        }
 
        try {
            Statement statement = CCJSqlParserUtil.parse(sql);
            if (!(statement instanceof Select)) {
                return super.autoCountSql(page, sql);
            }
 
            Select select = (Select) statement;
            PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
 
            // If SQL has WHERE conditions, delegate to parent's full COUNT rewriting
            if (plainSelect.getWhere() != null) {
                return super.autoCountSql(page, sql);
            }
 
            // No WHERE clause — this is the "browse all records" case.
            // Return minimal COUNT query so InnoDB picks the smallest index.
            if (plainSelect.getFromItem() != null) {
                String tableName = plainSelect.getFromItem().toString();
                return "SELECT COUNT(*) FROM " + tableName;
            }
        } catch (JSQLParserException e) {
            log.debug("SQL parsing failed for fast count, using default: {}", e.getMessage());
        }
 
        return super.autoCountSql(page, sql);
    }
}