Note:
This topic has been translated from a Chinese forum by GPT and might contain errors.Original topic: 慢查优化,不走索引
[TiDB Usage Environment] Production Environment / Testing / Poc
[TiDB Version]
[Reproduction Path] What operations were performed that caused the issue
[Encountered Issue: Issue Phenomenon and Impact]
[Resource Configuration] Go to TiDB Dashboard - Cluster Info - Hosts and take a screenshot of this page
[Attachments: Screenshots / Logs / Monitoring]
Query whether a certain user exists in the risk table
SELECT risk_value AS risk_t
FROM user_risk
WHERE risk_value = (
SELECT mobile
FROM user
WHERE id = 12345
)
AND risk_item = 1
AND risk_type = 1
AND is_deleted = 0
AND status = 1
Table structure
CREATE TABLE `user_risk` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Primary key id',
...
`risk_item` smallint(2) NOT NULL COMMENT 'Risk item',
`risk_type` smallint(2) NOT NULL COMMENT 'Risk type',
`risk_value` varchar(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT 'Value corresponding to the risk item, mixed type',
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,
...
KEY `risk_value` (`risk_item`,`risk_type`,`risk_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci AUTO_INCREMENT=8536500 COMMENT='Risk table'
CREATE TABLE `user` (
`id` bigint(20) NOT NULL COMMENT 'Account id',
`mobile` varchar(32) DEFAULT '' COMMENT 'Mobile number',
...
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */,
...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='Account table'
Executing the following query can use the composite index
SELECT risk_value AS risk_t
FROM user_risk
WHERE risk_value = (
SELECT mobile
FROM user
WHERE id = 12345
)
AND risk_item = 1
AND risk_type = 1
+-----------------------------+------------+-----------+---------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+-----------------------------+------------+-----------+---------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+
| Projection_11 | 2433100.99 | root | | user_risk.risk_value |
| └─IndexReader_14 | 2433100.99 | root | | index:Selection_13 |
| └─Selection_13 | 2433100.99 | cop[tikv] | | eq(user_risk.risk_value, "xxx") |
| └─IndexRangeScan_12 | 3041376.23 | cop[tikv] | table:user_risk, index:idx_risk_value(risk_item, risk_type, risk_value) | range:[1 1,1 1], keep order:false |
+-----------------------------+------------+-----------+---------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------+
If you add is_deleted=0 and status=1, it will perform a full table scan
+----------------------------+------------+-----------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| id | estRows | task | access object | operator info |
+----------------------------+------------+-----------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Projection_11 | 2351569.96 | root | | user_risk.risk_value |
| └─TableReader_14 | 2351569.96 | root | | data:Selection_13 |
| └─Selection_13 | 2351569.96 | cop[tikv] | | eq(user_risk.risk_value, "xxx"), eq(user_risk.is_deleted, 0), eq(user_risk.risk_item, 1), eq(user_risk.risk_type, 1), eq(user_risk.status, 1) |
| └─TableFullScan_12 | 8450909.00 | cop[tikv] | table:user_risk | keep order:false |
+----------------------------+------------+-----------+---------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
How to optimize this? According to business requirements, executing select id from user where id=12345 and exist(select * from user_risk where user_risk=mobile and ....)
is more semantically appropriate, but slower.