我有一个存储用户数据的表,它目前有超过1亿条数据。
由于这个表有大量的数据,涉及日期范围的查询非常慢。例如,在这个表中,有一个日期类型的出生列,我们在其中做了很多事情,如示例所示:
SELECT * FROM USERS WHERE YEAR(CURDATE() - YEAR(birth) > 15
为了提高这些查询的性能,我考虑将该表按年份划分为93个分区。
我考虑过分区,例如,像这样的列表:
ALTER TABLE USERS
PARTITION BY range(year(birth))(
PARITTION p_year_1930 VALUES LESS THAN (1930),
PARITTION p_year_1931 VALUES LESS THAN (1931),
...
PARITTION p_year_1930 VALUES LESS THAN (2023),
)
使用hash:
PARTITION BY hash(year(birth))(
partitions 93
)
我的问题是,在这种情况下,分区是否是一个好的策略,或者是否有另一个更好的解决方案,例如使用索引键,以及在这种情况下使用hash或range在性能方面是否存在差异,考虑使用这个where子句的查询:YEAR(CURDATE()) - YEAR(birth) > 15
@编辑
根据@Schwern的要求,我的表的结构:
client_inss_dados | CREATE TABLE `client_inss_dados` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`SSN` varchar(50) DEFAULT NULL,
`NAME` varchar(255) DEFAULT NULL,
`SEX` varchar(255) DEFAULT NULL,
`BIRTH` varchar(255) DEFAULT NULL,
`WAGE` varchar(255) DEFAULT NULL,
`COD_BANK` varchar(255) DEFAULT NULL,
`ADDRESS` varchar(255) DEFAULT NULL,
`CITY` varchar(255) DEFAULT NULL,
`PHONE_01` varchar(255) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
PRIMARY KEY (`ID`) USING BTREE,
KEY `idx_SSN` (`SSN`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT VERSION();
10.5.19-MariaDB
1条答案
按热度按时间sqougxex1#
正如@Schwern所指出的,创建一个出生年份的列,可以是generated column。
使用索引的一般原则是它是一个暴露的值,而不是SQL中的表达式。所以:
使用
EXPLAIN {query}
查看是否使用了索引yr_index
。MariaDB-11.1 preview刚刚推出了一些功能来简化应用于列的
YEAR
函数,以便在date
/datetime
/timestamp
列上使用索引。因此,第一步是将
BIRTH
存储为date
类型,并在其上创建索引:如fiddle所示,正确日期格式的BIRTH将被转换。
使用MariaDB-11.1预览功能,只需要对查询进行一个小的重新排列(MariaDB中没有实现对数学表达式/关系进行复杂的重新排列以匹配索引)。
如果在预览阶段没有发现此实现的主要问题,未来的11.1和更高版本将具有此功能。在11.1预览结束后检查MDEV-8320的固定版本以检查是否包含此功能。