{"record":{"id":"2c1dbb85f4fa355f","repo":"baomidou/mybatis-plus","slug":"sql-sql-table-columnname-2c1dbb","errorCode":null,"errorMessage":"非法SQL，SQL未使用到索引, table:{}, columnName:{}","messagePattern":"非法SQL，SQL未使用到索引, table:(.+?), columnName:(.+?)","errorType":"exception","errorClass":"MybatisPlusException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/IllegalSQLInnerInterceptor.java","lineNumber":248,"sourceCode":"    private void validUseIndex(Table table, String columnName, Connection connection) {\n        //是否使用索引\n        boolean useIndexFlag = false;\n        if (StringUtils.isNotBlank(columnName)) {\n            //表存在的索引\n            String dbName = table.getSchemaName();\n            String tableName = table.getName();\n            String catalogName = table.getCatalogName();\n            columnName = SqlParserUtils.removeWrapperSymbol(columnName);\n            List<IndexInfo> indexInfos = getIndexInfos(catalogName, dbName, tableName, connection);\n            for (IndexInfo indexInfo : indexInfos) {\n                if (indexInfo.getColumnName().equalsIgnoreCase(columnName)) {\n                    useIndexFlag = true;\n                    break;\n                }\n            }\n        }\n        if (!useIndexFlag) {\n            throw new MybatisPlusException(\"非法SQL，SQL未使用到索引, table:\" + table.getName() + \", columnName:\" + columnName);\n        }\n    }\n\n    /**\n     * 验证where条件的字段，是否有not、or等等，并且where的第一个字段，必须使用索引\n     *\n     * @param expression ignore\n     * @param table      ignore\n     * @param connection ignore\n     */\n    private void validWhere(Expression expression, Table table, Connection connection) {\n        validWhere(expression, table, null, connection);\n    }\n\n    /**\n     * 验证where条件的字段，是否有not、or等等，并且where的第一个字段，必须使用索引\n     *\n     * @param expression ignore","sourceCodeStart":230,"sourceCodeEnd":266,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-jsqlparser-support/mybatis-plus-jsqlparser-5.0/src/main/java/com/baomidou/mybatisplus/extension/plugins/inner/IllegalSQLInnerInterceptor.java#L230-L266","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Add an index on the leading WHERE column: CREATE INDEX idx_order_status ON t_order(status)","Reorder the WHERE clause so an indexed column comes first in the parsed expression","Verify the connected database/catalog actually contains the index (check SHOW INDEX / user_indexes) — wrong dbName or catalog in getIndexInfos makes every lookup fail","If full-table scans are intentional (small tables, reports), disable the index-check portion or the whole IllegalSQLInnerInterceptor for that statement/environment"],"exampleFix":"-- before: SELECT * FROM t_order WHERE status = ?;  -- status not indexed\nCREATE INDEX idx_t_order_status ON t_order(status);\n-- after: SELECT * FROM t_order WHERE status = ?;  -- interceptor passes","handlingStrategy":"try-catch","validationCode":"// Verify the leading WHERE column is indexed before running intercepted SQL\ntry (Connection c = dataSource.getConnection()) {\n    DatabaseMetaData md = c.getMetaData();\n    boolean indexed;\n    try (ResultSet rs = md.getIndexInfo(null, null, \"t_order\", false, false)) {\n        indexed = false;\n        while (rs.next()) {\n            if (\"status\".equalsIgnoreCase(rs.getString(\"COLUMN_NAME\"))) { indexed = true; break; }\n        }\n    }\n    if (!indexed) throw new IllegalStateException(\"t_order.status has no index; interceptor will reject\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    return orderMapper.selectByStatus(status);\n} catch (MybatisPlusException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"未使用到索引\")) {\n        // route to a statement whose leading column is indexed, or surface an ops error\n        throw new IllegalStateException(\"Leading WHERE column lacks index — create one or reorder predicates\", e);\n    }\n    throw e;\n}","preventionTips":["Add indexes for columns used as leading WHERE predicates before enabling the interceptor","Keep schema migrations and interceptor rollout in the same release train","Ensure the JDBC URL's schema/catalog matches where indexes were created"],"tags":["mybatis-plus","sql","index","performance","interceptor"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}