فهرست منبع

JsqlParserCountOptimize 对left join 的 sql 进行一下简单的处理,使count更精确

miemie 6 سال پیش
والد
کامیت
76887bb143

+ 26 - 0
mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/plugins/pagination/optimize/JsqlParserCountOptimize.java

@@ -20,11 +20,13 @@ import com.baomidou.mybatisplus.core.parser.SqlInfo;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
+import net.sf.jsqlparser.expression.Alias;
 import net.sf.jsqlparser.expression.Expression;
 import net.sf.jsqlparser.expression.Function;
 import net.sf.jsqlparser.expression.LongValue;
 import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
 import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.schema.Table;
 import net.sf.jsqlparser.statement.select.*;
 import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.logging.LogFactory;
@@ -32,6 +34,7 @@ import org.apache.ibatis.reflection.MetaObject;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Optional;
 
 /**
  * JsqlParser Count Optimize
@@ -93,6 +96,29 @@ public class JsqlParserCountOptimize implements ISqlParser {
             if (distinct != null || CollectionUtils.isNotEmpty(groupBy)) {
                 return sqlInfo.setSql(SqlParserUtils.getOriginalCountSql(selectStatement.toString()));
             }
+            // 包含 join 连表,进行判断是否移除 join 连表
+            List<Join> joins = plainSelect.getJoins();
+            if (CollectionUtils.isNotEmpty(joins)) {
+                boolean canRemoveJoin = true;
+                String whereS = Optional.ofNullable(plainSelect.getWhere()).map(Expression::toString).orElse(StringPool.EMPTY);
+                for (Join join : joins) {
+                    if (!join.isLeft()) {
+                        canRemoveJoin = false;
+                        break;
+                    }
+                    Table table = (Table) join.getRightItem();
+                    String str = Optional.ofNullable(table.getAlias()).map(Alias::getName).orElse(table.getName()) + StringPool.DOT;
+                    String onExpressionS = join.getOnExpression().toString();
+                    /* 如果 join 里包含 ?(代表有入参) 或者 where 条件里包含使用 join 的表的字段作条件,就不移除 join */
+                    if (onExpressionS.contains(StringPool.QUESTION_MARK) || whereS.contains(str)) {
+                        canRemoveJoin = false;
+                        break;
+                    }
+                }
+                if (canRemoveJoin) {
+                    plainSelect.setJoins(null);
+                }
+            }
             // 优化 SQL
             plainSelect.setSelectItems(COUNT_SELECT_ITEM);
             return sqlInfo.setSql(selectStatement.toString());

+ 33 - 0
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/plugins/pagination/optimize/JsqlParserCountOptimizeTest.java

@@ -0,0 +1,33 @@
+package com.baomidou.mybatisplus.extension.plugins.pagination.optimize;
+
+import org.apache.ibatis.reflection.MetaObject;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * @author miemie
+ * @since 2019-05-08
+ */
+class JsqlParserCountOptimizeTest {
+
+    private JsqlParserCountOptimize parser = new JsqlParserCountOptimize();
+    private MetaObject metaObject = null;
+
+    @Test
+    void parserLeftJoin() {
+        /* 能进行优化的 SQL */
+        assertThat(parser.parser(metaObject, "select * from user u LEFT JOIN role r ON r.id = u.role_id WHERE u.xx = ?").getSql())
+            .isEqualTo("SELECT COUNT(1) FROM user u WHERE u.xx = ?");
+
+        assertThat(parser.parser(metaObject, "select * from user LEFT JOIN role ON role.id = user.role_id WHERE user.xx = ?").getSql())
+            .isEqualTo("SELECT COUNT(1) FROM user WHERE user.xx = ?");
+
+        /* 不能进行优化的 SQL */
+        assertThat(parser.parser(metaObject, "select * from user u LEFT JOIN role r ON r.id = u.role_id AND r.name = ? where u.xx = ?").getSql())
+            .isEqualTo("SELECT COUNT(1) FROM user u LEFT JOIN role r ON r.id = u.role_id AND r.name = ? WHERE u.xx = ?");
+
+        assertThat(parser.parser(metaObject, "select * from user u LEFT JOIN role r ON r.id = u.role_id WHERE u.xax = ? AND r.cc = ? AND r.qq = ?").getSql())
+            .isEqualTo("SELECT COUNT(1) FROM user u LEFT JOIN role r ON r.id = u.role_id WHERE u.xax = ? AND r.cc = ? AND r.qq = ?");
+    }
+}

+ 0 - 32
mybatis-plus-extension/src/test/java/com/baomidou/mybatisplus/extension/toolkit/SqlParserUtilsTest.java

@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2011-2019, hubin (jobob@qq.com).
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- * <p>
- * https://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.baomidou.mybatisplus.extension.toolkit;
-
-
-import org.junit.jupiter.api.Test;
-
-/**
- * @author miemie
- * @since 2019-02-22
- */
-class SqlParserUtilsTest {
-
-    @Test
-    void getOptimizeCountSql() {
-        System.out.println(SqlParserUtils.getOptimizeCountSql(true, null,
-            "SELECT id,name,age,email,merge FROM user").getSql());
-    }
-}