baomidou/mybatis-plus · error · MybatisPlusException

非法SQL,SQL未使用到索引, table:{}, columnName:{}

Error message

非法SQL,SQL未使用到索引, table:{}, columnName:{}

What it means

Thrown by IllegalSQLInnerInterceptor (jsqlparser 5.0 variant) during index validation: after collecting IndexInfo metadata from the JDBC connection, if the first WHERE column of the table does not match any indexed column name, the interceptor rejects the SQL as '未使用到索引' (no index used), naming the table and column. It enforces the rule that the leading WHERE predicate must hit an index.

Source

Thrown at mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/IllegalSQLInnerInterceptor.java:248

    private void validUseIndex(Table table, String columnName, Connection connection) {
        //是否使用索引
        boolean useIndexFlag = false;
        if (StringUtils.isNotBlank(columnName)) {
            //表存在的索引
            String dbName = table.getSchemaName();
            String tableName = table.getName();
            String catalogName = table.getCatalogName();
            columnName = SqlParserUtils.removeWrapperSymbol(columnName);
            List<IndexInfo> indexInfos = getIndexInfos(catalogName, dbName, tableName, connection);
            for (IndexInfo indexInfo : indexInfos) {
                if (indexInfo.getColumnName().equalsIgnoreCase(columnName)) {
                    useIndexFlag = true;
                    break;
                }
            }
        }
        if (!useIndexFlag) {
            throw new MybatisPlusException("非法SQL,SQL未使用到索引, table:" + table.getName() + ", columnName:" + columnName);
        }
    }

    /**
     * 验证where条件的字段,是否有not、or等等,并且where的第一个字段,必须使用索引
     *
     * @param expression ignore
     * @param table      ignore
     * @param connection ignore
     */
    private void validWhere(Expression expression, Table table, Connection connection) {
        validWhere(expression, table, null, connection);
    }

    /**
     * 验证where条件的字段,是否有not、or等等,并且where的第一个字段,必须使用索引
     *
     * @param expression ignore

View on GitHub (pinned to bf67d90747)

Solutions

  1. Add an index on the leading WHERE column: CREATE INDEX idx_order_status ON t_order(status)
  2. Reorder the WHERE clause so an indexed column comes first in the parsed expression
  3. Verify the connected database/catalog actually contains the index (check SHOW INDEX / user_indexes) — wrong dbName or catalog in getIndexInfos makes every lookup fail
  4. If full-table scans are intentional (small tables, reports), disable the index-check portion or the whole IllegalSQLInnerInterceptor for that statement/environment

Example fix

-- before: SELECT * FROM t_order WHERE status = ?;  -- status not indexed
CREATE INDEX idx_t_order_status ON t_order(status);
-- after: SELECT * FROM t_order WHERE status = ?;  -- interceptor passes
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify the leading WHERE column is indexed before running intercepted SQL
try (Connection c = dataSource.getConnection()) {
    DatabaseMetaData md = c.getMetaData();
    boolean indexed;
    try (ResultSet rs = md.getIndexInfo(null, null, "t_order", false, false)) {
        indexed = false;
        while (rs.next()) {
            if ("status".equalsIgnoreCase(rs.getString("COLUMN_NAME"))) { indexed = true; break; }
        }
    }
    if (!indexed) throw new IllegalStateException("t_order.status has no index; interceptor will reject");
}

Try / catch

try {
    return orderMapper.selectByStatus(status);
} catch (MybatisPlusException e) {
    if (e.getMessage() != null && e.getMessage().contains("未使用到索引")) {
        // route to a statement whose leading column is indexed, or surface an ops error
        throw new IllegalStateException("Leading WHERE column lacks index — create one or reorder predicates", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Registering IllegalSQLInnerInterceptor (optionally with index check enabled) and executing a query whose first WHERE column has no matching index in DatabaseMetaData — e.g. WHERE status = ? where status is a non-indexed column, or where the column is wrapped/aliased so its name doesn't string-match an IndexInfo column.

Common situations: Enabling the interceptor on a schema where leading filter columns lack indexes; case/schema mismatch between the mapper column name and JDBC metadata; developers testing against H2 where production MySQL indexes don't exist; hitting the check on large full-table-scan reports.

Related errors


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/2c1dbb85f4fa355f. Report an issue: GitHub.