planner: prepared statement unexpectedly reuses cached plan for decimal range query
- Dominant language
- Go
- Stars
- 40.5k
- Forks
- 6.2k
- PR merge metrics
- PR metrics pending
Description
---
name: "🐛 Bug Report"
about: As a User, I want to report a Bug.
labels: type/bug
---
## Bug Report
Please answer these questions before submitting your issue. Thanks!
### 1. Minimal reproduce step (Required)
Use the following minimal schema and data extracted from the Shiro report `case_0004_019d25f3-2ddf-7061-a79f-7030dfc82ef3`.
```sql
CREATE TABLE `t1` (
`id` bigint NOT NULL,
`c0` decimal(12,2) NOT NULL,
`c1` date NOT NULL,
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,
KEY `idx_c0` (`c0`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
```
Load data into t1
```sql
INSERT INTO t1 (id, c0, c1) VALUES (255, 69.59, '2025-08-28'), (256, 50.37, '2024-05-08'), (257, 13.83, '2024-04-03');
INSERT INTO t1 (id, c0, c1) VALUES (258, 51.52, '2023-07-30'), (259, 51.8, '2024-06-20'), (260, 75.08, '2024-12-28');
INSERT INTO t1 (id, c0, c1) VALUES (261, 74.37, '2024-06-06'), (262, 23.25, '2025-08-29');
INSERT INTO t1 (id, c0, c1) VALUES (263, 82.76, '2026-10-31'), (264, 53.85, '2026-12-19'), (265, 17.82, '2025-11-08');
INSERT INTO t1 (id, c0, c1) VALUES (266, 35.71, '2023-08-22'), (267, 43.08, '2025-07-03');
INSERT INTO t1 (id, c0, c1) VALUES (268, 19.74, '2023-06-14'), (269, 23.9, '2026-02-26');
INSERT INTO t1 (id, c0, c1) VALUES (270, 91.8, '2023-07-20'), (271, 32.88, '2024-03-16'), (272, 41.33, '2024-06-17');
INSERT INTO t1 (id, c0, c1) VALUES (273, 55.76, '2026-04-27');
INSERT INTO t1 (id, c0, c1) VALUES (274, 14.44, '2026-05-09');
INSERT INTO t1 (id, c0, c1) VALUES (275, 25.79, '2023-01-30'), (276, 61.92, '2024-02-28'), (277, 65.93, '2025-08-23');
INSERT INTO t1 (id, c0, c1) VALUES (278, 5.41, '2026-12-24'), (279, 62.95, '2026-10-31'), (280, 93.9, '2025-11-01');
INSERT INTO t1 (id, c0, c1) VALUES (281, 94.07, '2023-08-16');
INSERT INTO t1 (id, c0, c1) VALUES (282, 38.51, '2026-03-31');
INSERT INTO t1 (id, c0, c1) VALUES (283, 29.32, '2026-09-07'), (284, 17.16, '2024-10-26');
INSERT INTO t1 (id, c0, c1) VALUES (285, 90.11, '2025-01-15'), (286, 48.33, '2026-05-16'), (287, 79.75, '2024-04-13');
INSERT INTO t1 (id, c0, c1) VALUES (288, 44.55, '2025-01-19');
INSERT INTO t1 (id, c0, c1) VALUES (289, 55.48, '2023-04-30'), (290, 80.48, '2023-01-06'), (291, 7.67, '2026-05-12');
INSERT INTO t1 (id, c0, c1) VALUES (292, 71.11, '2025-05-26'), (293, 74.29, '2026-03-11'), (294, 48.1, '2026-11-14');
INSERT INTO t1 (id, c0, c1) VALUES (295, 84.37, '2025-12-24'), (296, 51.46, '2025-04-22'), (297, 85.01, '2025-01-12');
INSERT INTO t1 (id, c0, c1) VALUES (298, 53.47, '2023-10-15'), (299, 43.53, '2026-08-12');
INSERT INTO t1 (id, c0, c1) VALUES (300, 61.77, '2024-03-15');
INSERT INTO t1 (id, c0, c1) VALUES (301, 33.8, '2023-10-23'), (302, 78.43, '2025-07-22'), (303, 22.3, '2023-11-25');
INSERT INTO t1 (id, c0, c1) VALUES (304, 70.93, '2023-12-22'), (305, 46.54, '2023-01-15'), (306, 93.79, '2026-07-23');
INSERT INTO t1 (id, c0, c1) VALUES (307, 51.57, '2025-02-10');
INSERT INTO t1 (id, c0, c1) VALUES (308, 36.95, '2024-08-22'), (309, 73.37, '2023-09-19'), (310, 5.06, '2025-08-06');
INSERT INTO t1 (id, c0, c1) VALUES (311, 95.52, '2023-06-26'), (312, 12.27, '2025-04-30');
INSERT INTO t1 (id, c0, c1) VALUES (313, 51.71, '2023-01-09'), (314, 27.42, '2023-04-08'), (315, 10.2, '2023-04-05');
INSERT INTO t1 (id, c0, c1) VALUES (316, 69.15, '2026-07-13'), (317, 76.79, '2024-03-11');
INSERT INTO t1 (id, c0, c1) VALUES (318, 38.57, '2026-02-21'), (319, 60.41, '2026-06-06');
INSERT INTO t1 (id, c0, c1) VALUES (320, 77.08, '2024-03-09'), (321, 75.16, '2025-07-19'), (322, 76.44, '2025-05-16');
INSERT INTO t1 (id, c0, c1) VALUES (323, 14.91, '2024-02-06'), (324, 6.48, '2023-05-11');
INSERT INTO t1 (id, c0, c1) VALUES (325, 24.78, '2023-03-25');
INSERT INTO t1 (id, c0, c1) VALUES (326, 77.45, '2026-08-20'), (327, 83.1, '2023-07-10');
INSERT INTO t1 (id, c0, c1) VALUES (328, 52.63, '2024-08-09');
INSERT INTO t1 (id, c0, c1) VALUES (329, 37.34, '2026-05-23'), (330, 48.73, '2026-04-05'), (331, 26.45, '2023-07-20');
INSERT INTO t1 (id, c0, c1) VALUES (332, 18.73, '2025-12-11'), (333, 79.71, '2026-04-08'), (334, 84.99, '2023-12-23');
```
Run the following SQL:
```sql
SELECT COUNT(*) AS cnt, SUM(c0) AS sum1
FROM t1
WHERE c0 > 3.49 AND c0 < 40.06;
PREPARE stmt FROM 'SELECT COUNT(*) AS cnt, SUM(c0) AS sum1 FROM t1 WHERE c0 > ? AND c0 < ?';
SET @p1 = 30.31, @p2 = 74.77;
EXECUTE stmt USING @p1, @p2;
SELECT @@last_plan_from_cache;
SET @p1 = 3.49, @p2 = 40.06;
EXECUTE stmt USING @p1, @p2;
SELECT @@last_plan_from_cache;
```
Observed from the Shiro report:
- Oracle: `PlanCache`
- Expected: `last_plan_from_cache=0`
- Actual: `last_plan_from_cache=1`
- `flaky=false`
- Plan replayer: `reports/case_0004_019d25f3-2ddf-7061-a79f-7030dfc82ef3/plan_replayer.zip`
### 2. What did you expect to see? (Required)
For the parameter set `(@p1 = 3.49, @p2 = 40.06)`, TiDB should not reuse the cached plan and `@@last_plan_from_cache` should be `0`.
### 3. What did you see instead (Required)
TiDB reports `@@last_plan_from_cache = 1`, which means the prepared statement unexpectedly reuses a cached plan after switching from `(30.31, 74.77)` to `(3.49, 40.06)`.
### 4. What is your TiDB version? (Required)
```sql
Release Version: rc2-23450-g2ec17cff63
Edition: Community
Git Commit Hash: 2ec17cff63dbb3ae4a7040265f906b09b82c31c0
Git Branch: 65791
UTC Build Time: 2026-03-25 16:31:40
GoVersion: go1.25.8
Race Enabled: false
Check Table Before Drop: false
Store: tikv
Kernel Type: Classic
```
## Analysis
- This looks like a parameter-sensitive plan cache issue on a decimal range predicate over `t1.c0` with index `idx_c0`. The prepared statement is reused across materially different selectivity ranges.
- The cacheability decision or cache key likely does not fully account for bound-value effects on range access for `decimal(12,2)` predicates. Evidence: the literal query for `3.49 < c0 < 40.06` is expected to be a non-cache hit, but the prepared execution reports `@@last_plan_from_cache = 1`.
- The attached plan replayer should help confirm whether the reused cached plan comes from the first execution with `(30.31, 74.77)` and whether the second execution should have taken a different access path or been marked non-cacheable.
Contributor guide
Assessment
This issue has not been assessed yet.