Ste*_*one 7 mysql sql select virtual-column
我正在使用MySQL 5.7.我创建了一个带有DATETIME类型的虚拟列(未存储)的表,其中包含索引.当我正在研究它时,我注意到order by并没有返回所有数据(我在顶部期待的一些数据丢失了).MAX和MIN的结果也是错误的.我跑完之后
ANALYZE TABLE
CHECK TABLE
OPTIMIZE TABLE
Run Code Online (Sandbox Code Playgroud)
然后结果是正确的.我想索引数据存在问题,所以我几乎没有问题:
我担心将来会发生这种情况,但我不会注意到.
编辑:
根据评论中的要求,我添加了表定义:
CREATE TABLE `items` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned DEFAULT NULL,
`image` json DEFAULT NULL,
`status` json DEFAULT NULL,
`status_expired` tinyint(1) GENERATED ALWAYS AS (ifnull(json_contains(`status`,'true','$.expired'),false)) VIRTUAL COMMENT 'used for index: it checks if status contains expired=true',
`lifetime` tinyint(4) NOT NULL,
`expiration` datetime GENERATED ALWAYS AS ((`create_date` + interval `lifetime` day)) VIRTUAL,
`last_update` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `expiration` (`status_expired`,`expiration`) USING BTREE,
CONSTRAINT `ts_competition_item_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `ts_user_core` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1312459 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED
Run Code Online (Sandbox Code Playgroud)
返回错误结果的查询:
SELECT * FROM items ORDER BY expiration DESC;
SELECT max(expiration),min(expiration) FROM items;
Run Code Online (Sandbox Code Playgroud)
谢谢
问题是您的数据来自通过索引实现的虚拟列.检查,优化,分析您正在执行的操作会强制同步索引并修复任何错误.从而为您提供正确的结果.至少在索引再次失去同步之前.
许多问题都是由您的表格设计问题引起的.让我们开始吧.
`status_expired` tinyint(1) GENERATED ALWAYS AS (ifnull(json_contains(`status`,'true','$.expired'),false)) VIRTUAL
Run Code Online (Sandbox Code Playgroud)
毫无疑问,这是为了克服你无法直接索引JSONmysql中的列这一事实而创建的.您已创建了一个虚拟列,并将其编入索引.这一切都很好,但是这个列只能包含两个值中的一个; true或false.这意味着它的基数很差.因此,mysql不太可能将此索引用于任何事情.
但是我们可以看到在创建索引时已将status_expired列与expired列组合在一起.也许是为了克服上面提到的这种可怜的基数.可是等等...
`expiration` datetime GENERATED ALWAYS AS ((`create_date` + interval `lifetime` day)) VIRTUAL,
Run Code Online (Sandbox Code Playgroud)
到期是另一个虚拟列.这会产生一些影响.
在生成的虚拟列上创建辅助索引时,生成的列值将在索引的记录中实现.如果索引是覆盖索引(包括查询检索的所有列的索引),则从索引结构中的具体化值中检索生成的列值,而不是"在运行中"计算.
参考:https://dev.mysql.com/doc/refman/5.7/en/create-table-secondary-indexes.html#json-column-indirect-index
这与之相反
VIRTUAL:不存储列值,但在任何BEFORE触发器之后立即读取行时计算列值.虚拟列不占用存储空间.
参考:https://dev.mysql.com/doc/refman/5.7/en/create-table-generated-columns.html
我们基于声音主体创建虚拟列,不应存储由列上的简单操作生成的值以避免冗余,但通过在其上创建索引,我们重新引入冗余.
根据提供的信息,您似乎不需要status_expired列甚至expired列.超过它的失效日期的项目已过期!
CREATE TABLE `items` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned DEFAULT NULL,
`image` json DEFAULT NULL,
`status` json DEFAULT NULL,
`expire_date` datetime GENERATED ALWAYS AS ((`create_date` + interval `lifetime` day)) VIRTUAL,
`last_update` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`create_date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`),
KEY `expiration` (`expired_date`) USING BTREE,
CONSTRAINT `ts_competition_item_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `ts_user_core` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1312459 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=COMPRESSED
Run Code Online (Sandbox Code Playgroud)
当您需要找出哪些项目已过期时,只需将当前日期与上表中的expired_date列进行比较.这里的区别不是expired在每个查询中都是计算项,而是在expiry_date创建记录时计算一次.
这使得你的桌子更整洁,查询可能更快
| 归档时间: |
|
| 查看次数: |
1170 次 |
| 最近记录: |