在我的公司,我们有一张桌子变得太大了。它只有4个字段,下面共享索引。请注意,我们的数据是按地区分开的,因此我们在两个独立的数据库中有相同的模式(一个用于NA,一个用于EU)。以下数据是针对欧盟的,但北美的数据通常是欧盟的10倍。
领域
|
类型
|
无效的
|
钥匙
|
违约
|
额外的
|
id
|
bigint(20)unsigned
|
没有
|
PRI
|
NULL
|
自动更正
|
其他表_id
|
int(11)
|
没有
|
MUL
|
NULL
|
|
时间索引
|
int(11)
|
没有
|
|
NULL
|
|
价值
|
十进制(18,6)
|
是的
|
|
NULL
|
|
桌子
|
非唯一(_U)
|
密钥名称
|
序列索引
|
列名称
|
排序规则
|
基数
|
子部件(_P)
|
拥挤的
|
无效的
|
索引类型
|
议论
|
索引_注释
|
我的表(_T)
|
0
|
初级
|
1.
|
id
|
a.
|
833155696
|
NULL
|
NULL
|
|
BTREE
|
|
|
我的表(_T)
|
0
|
索引其他表和时间索引
|
1.
|
其他表_id
|
a.
|
29755560
|
NULL
|
NULL
|
|
BTREE
|
|
|
我的表(_T)
|
0
|
索引其他表和时间索引
|
2.
|
时间索引
|
a.
|
833155696
|
NULL
|
NULL
|
|
BTREE
|
|
|
请注意,other_table_id是另一个表的id,但它不是在数据库级别强制执行的。(在rails应用程序级别强制执行)。还要注意,非主索引有一个唯一的约束。
我们在这个表上实际上只有两个查询。我们的插页是以下形式的批量插页:
INSERT INTO my_table (value, time_index, other_table_id)
VALUES (1,2,3),(4,5,6)...<5000-10000 tuples later>... (7,8,9)
ON DUPLICATE KEY UPDATE
my_table.value=VALUES(value),
my_table.time_index=VALUES(time_index),
my_table.other_table_id=VALUES(other_table_id);
我们的查询如下:
select other_table_id, time_index, value from my_table where
(other_table_id in (<3000 values>) and time_index between 5800 and 6050 )
or (other_table_id in (<300 values>) and time_index between 800 and 830)
order by other_table_id, time_index;
自2006年以来,这张表一直在增长。我们看到查询和插入时间>频繁60秒。(可以在mysql慢速查询日志中看到)。我们正在使用RDS中提供的最大实例AWS,并且我们已经调整了IO/内存。
因此,我正在尝试想出其他方法来提高性能。
我想知道删除id字段是否会给我带来重大好处?在这种情况下,插入过程中所需的值会减少一个。我还考虑了基于时间索引的分区,因为大多数查询都使用最近的时间索引。然而,我读到分区会使数据库离线,我会害怕对这么大的数据库进行分区。目前还不清楚数据库会关闭多久。
删除id字段会给我带来什么主要好处吗?分区会给我带来很大的好处吗?如果是这样,有没有一种方法可以在不停机的情况下进行分区?注意,我必须在分区之前删除id字段,因为mysql要求所有索引键都在分区中。我在考虑在time_index上进行分区。
还有什么其他选择?我们没有读取副本,所以另一种选择是将读取查询移动到读取副本。然而,我不清楚这是否会取得重大胜利,因为我们的问题是更多的桌子大小而不是负载。请注意,EU约有8.33亿行,而NA约有3.9亿行。
编辑:对于澄清来说,价值是一种科学的衡量标准。我不确定业务是否允许我编辑它。我还在下面的阅读查询中添加了解释查询:
id
|
select_type
|
桌子
|
类型
|
可能的密钥
|
钥匙
|
key_len
|
参考
|
行
|
额外的
|
1.
|
简单的
|
我的表(_T)
|
范围
|
索引其他表和时间索引
|
索引其他表和时间索引
|
8.
|
NULL
|
3432
|
使用索引条件
|
还添加了对联合建议的解释查询:
id
|
select_type
|
桌子
|
类型
|
可能的密钥
|
钥匙
|
key_len
|
参考
|
行
|
额外的
|
1.
|
初级
|
我的表(_T)
|
范围
|
索引其他表和时间索引
|
索引其他表和时间索引
|
8.
|
NULL
|
3118
|
使用索引条件
|
2.
|
联合
|
我的表(_T)
|
范围
|
索引其他表和时间索引
|
索引其他表和时间索引
|
8.
|
NULL
|
314
|
使用索引条件
|
NULL
|
并集结果
|
<uni1,2>
|
所有
|
NULL
|
NULL
|
NULL
|
NULL
|
NULL
|
使用临时;使用文件排序
|
根据请求,将语句解释为json:
{
"query_block": {
"select_id": 1,
"ordering_operation": {
"using_filesort": false,
"table": {
"table_name": "my_table",
"access_type": "range",
"possible_keys": [
"index_other_table_and_time_index"
],
"key": "index_other_table_and_time_index",
"used_key_parts": [
"other_table_id",
"time_index"
],
"key_length": "8",
"rows": 3432,
"filtered": 100,
"index_condition": "(((`mydb`.`my_table`.`other_table_id` in (...list of values)) and (`mydb`.`my_table`.`time_index` between 5800 and 6050)) or ((`mydb`.`my_table`.`other_table_id` in (...list of values...)) and (`mydb`.`my_table`.`time_index` between 800 and 830)))"
}
}
}
}