0

假设我正在使用data包含大约 1M 行的表运行 MySQL 8。我想过滤一个范围内的datetimedate(使用日期索引)。

CREATE TABLE `data` (
  `rowId` int NOT NULL AUTO_INCREMENT,
  `data` json NOT NULL,
  `created` DATETIME NOT NULL,                               -- <-- datetime column for a date index
  `created_date` DATE AS (cast(`created` as date)) NOT NULL, -- <-- generated date column
  PRIMARY KEY (`rowId`),
  INDEX (`created`),                                         -- <-- datetime index w/ cardinality ~ 1M 
  INDEX (`created_date`)                                     -- <-- date index w/ cardinality of 1250
  INDEX `created_cast` ((cast(`created` as date)))           -- <-- functional "date" index w/ cardinality of 1250
  --     ^ I WANT TO USE THIS INDEX, BUT DON'T KNOW HOW
) ENGINE=InnoDB;

然后让我们只过滤 2018 年的行,假设:

SELECT COUNT(*) FROM data
WHERE created >= CAST('2018-01-01' AS DATE) AND created < CAST('2019-01-01' AS DATE);
-- Query time: 0.16 s
-- EXPLAIN shows: key: created, Using where; Using index
-- Uses the whole datetime index w/ cardinality of ~ 1M 


SELECT COUNT(*) FROM data 
WHERE created_date BETWEEN CAST('2018-01-01' AS DATE) AND CAST('2018-12-31' AS DATE);
-- Query time: 0.09 s
-- EXPLAIN shows: key: created_date, Using where; Using index
-- Uses the date index w/ cardinality of 1250


SELECT COUNT(*) FROM data
WHERE CAST(created AS DATE) BETWEEN CAST('2018-01-01' AS DATE) AND CAST('2018-12-31' AS DATE);
-- Query time: 0.35 s, that's slow!
-- EXPLAIN shows: key: NULL, Using where
-- Doesn't use any index at all! 

有没有办法使用这个功能索引?

上面的查询使用created(datetime) 或created_date(date from generated column) 索引。

有没有办法直接使用功能索引 created_cast?我什至尝试过USE INDEXor FORCE INDEX,但没有运气。

谢谢你们 :)

4

1 回答 1

0

我会重写您的查询并删除CAST 并使用他生成的列,因为您没有转换,但它需要空间。

CREATE TABLE data (created datetime,
`created_date` DATE AS (cast(`created` as date)) NOT NULL,  INDEX testin (`created`),                                         -- <-- datetime index w/ cardinality ~ 1M 
  INDEX (`created_date`))
INSERt INTO data (created) VALUEs('2018-02-01'),('2018-02-01'),('2018-02-01'),('2018-02-01')
    SELECT COUNT(*) FROM data
    WHERE YEAR(`created`) = 2018;
    
| 计数(*) |
| --------: |
| 4 |
    SELECT COUNT(*) FROM data FORCE INDEX (testin)
    WHERE DATE(created) BETWEEN '2018-01-01' AND '2018-12-31';
| 计数(*) |
| --------: |
| 4 |
    EXPLAIN SELECT COUNT(*) FROM data FORCE INDEX (testin) 
    WHERE DATE(created) BETWEEN '2018-01-01' AND '2018-12-31'
编号 | 选择类型 | 表| 隔断 | 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 过滤 | 额外的                   
-: | :------------ | :---- | :--------- | :---- | :------------ | :----- | :-------- | :--- | ---: | --------: | :------------------------
 1 | 简单 | 数据 |        | 索引 |           | 测试 | 6 | | 4 | 100.00 | 使用哪里;使用索引
    SELECT COUNT(*) FROM data 
    WHERE created BETWEEN '2018-01-01 00:00:00' AND '2018-12-31 23:49:59';
| 计数(*) |
| --------: |
| 4 |
EXPLAIN     SELECT COUNT(*) FROM data 
    WHERE created BETWEEN '2018-01-01 00:00:00' AND '2018-12-31 23:49:59';
编号 | 选择类型 | 表| 隔断 | 类型 | 可能的键 | 关键 | key_len | 参考 | 行 | 过滤 | 额外的                   
-: | :------------ | :---- | :--------- | :---- | :------------ | :----- | :-------- | :--- | ---: | --------: | :------------------------
 1 | 简单 | 数据 |        | 索引 | 测试 | 测试 | 6 | | 4 | 100.00 | 使用哪里;使用索引

db<>在这里摆弄

于 2020-12-05T23:02:09.810 回答