有和没有分区性能问题的MySql表

问题描述 投票:0回答:1

我们有一个报告数据表,其中有数百万条记录。数据将增量添加到表中。使数据的获取和插入达到最佳状态。目前表中我们有 1 个公司和 10 个用户的大约 100K 测试数据行。

我们正在测试不同的选项。

  1. 对 company_id 和 user_id 列应用单独的索引。 (查询执行时间:687ms)

  2. 对列(company_id、user_id)应用组合索引。 (查询执行时间:1.1s)

  3. 应用主分区(company_id、user_id、id)以及company_id和user_id上的两个单独索引。 (查询执行时间:2.6s)

我们已在工单中附上表格和“解释”查询结果。

理论上,分区结果应该比普通索引是最优的,但正如您在下面的结果中看到的,分区遍历的行数比没有分区的要高得多,我们猜测这是造成这种情况的主要原因 分区性能缓慢。

我们已点击此链接分区参考来了解和应用分区。

有人可以指导我们对于大量数据(例如数据)是否真的需要分区吗? 3000万条记录或者索引可以吗?

(1)

CREATE TABLE `table1` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `company_id` int(11) NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `date` date DEFAULT NULL,
  `time_group` timestamp NULL DEFAULT NULL,
  `value` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_c_id` (`company_id`),
  KEY `idx_u_id` (`user_id`)
) 


EXPLAIN 
select company_id, sum(value) as result  
from table1 
where company_id = 55 
  and user_id in (127, 128, 129, 130, 132, 133) 
  and (time_group between '2024-01-01 00:00:00' and '2024-01-30 23:59:59') 
group by company_id 
order by result desc;

Query Explain Result without partition, with individual indexes

(2)

Query Explain Result without partition, with combined index

(3)

CREATE TABLE `table2` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `company_id` int(11) NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `date` date DEFAULT NULL,
  `time_group` timestamp NULL DEFAULT NULL,
  `value` int(11) DEFAULT NULL,
  PRIMARY KEY (`company_id`, `user_id`, `id`),
  KEY `idx_id` (`id`)
) PARTITION BY HASH(company_id) PARTITIONS 11;


EXPLAIN 
select company_id, sum(value) as result  
from table2 
where company_id = 55 
  and user_id in (127, 128, 129, 130, 132, 133) 
  and (time_group between '2024-01-01 00:00:00' and '2024-01-30 23:59:59') 
group by company_id 
order by result desc;

Query Explain Result with partition and individual indexes

我们已遵循此分区参考中提供的解决方案。但与上面解释的简单索引相比,分区的结果相对较慢。我们错过了什么吗?

此外,带有分区的索引大小很大。

SELECT 
    database_name, 
    table_name, 
    index_name,
    ROUND(stat_value * @@innodb_page_size / 1024 / 1024, 2) size_in_mb
FROM mysql.innodb_index_stats
WHERE stat_name = 'size' 
  AND index_name != 'PRIMARY' 
  and database_name = 'db'
ORDER BY size_in_mb DESC;

Index sizes

mysql performance indexing partitioning
1个回答
0
投票

我推荐这个不分区:

ADD TABLE table2
    DROP INDEX `idx_c_id`,   -- in the way
    ADD INDEX(company_id, user_id);

(另请参阅我的分区博客。)

如果(且仅当)您的大部分活动确实在月份范围内,那么

PARTITION BY RANGE(TO_DAYS(time_group)) ...

ADD TABLE table2
    DROP INDEX `idx_c_id`,   -- in the way
    ADD INDEX(company_id, user_id),    -- Optimizer may pick this

您的 MySQL 版本有多旧?我希望您的

EXLAIN
显示它使用(或未使用)的分区。对于旧版本,请使用
EXPLAIN EXTENDED SELECT ...

我推荐“月”范围的这种表述。 (没有性能差异;只是其他好处)

     time_group >= '2024-01-01'
 AND time_group  < '2024-01-01' + INTERVAL 1 MONTH
© www.soinside.com 2019 - 2024. All rights reserved.