我们有一个很大的MySQL表(device_data),其中包含以下列:
ID (int)
dt (timestamp)
serial_number (char(20))
data1 (double)
data2 (double)
... // other columns
该表每天接收约1000万行。
我们已经根据时间戳记日期(device_data_YYYYMMDD)分开了表格,从而进行了分片。但是,我们认为这并不有效,因为我们的大多数查询(如下所示)始终检查“ serial_number”,并且会在许多日期执行。
SELECT * FROM device_data WHERE serial_number = 'XXX' AND dt >= '2018-01-01' AND dt <= '2018-01-07';
因此,我们认为基于序列号创建分片会更有效。基本上,我们将有:
device_data_<serial_number>
device_data_0012393746
device_data_7891238456
因此,当我们要查找特定设备的数据时,我们可以轻松地引用为:
SELECT * FROM device_data_<serial_number> WHERE dt >= '2018-01-01' AND dt <= '2018-01-07';
这种方法似乎是有效的,因为:
我们认为我们将面临的一些挑战是:
更新。以下是现有表中的show create table结果:
CREATE TABLE `test_udp_new` (
`id` int(20) unsigned NOT NULL AUTO_INCREMENT,
`dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`device_sn` varchar(20) NOT NULL,
`gps_date` datetime NOT NULL,
`lat` decimal(10,5) DEFAULT NULL,
`lng` decimal(10,5) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `device_sn_2` (`dt`,`device_sn`),
KEY `dt` (`dt`),
KEY `data` (`data`) USING BTREE,
KEY `test_udp_new_device_sn_dt_index` (`device_sn`,`dt`),
KEY `test_udp_new_device_sn_data_dt_index` (`device_sn`,`data`,`dt`)
) ENGINE=InnoDB AUTO_INCREMENT=44449751 DEFAULT CHARSET=latin1 ROW_FORMAT=DYNAMIC
运行最频繁的查询:
SELECT *
FROM test_udp_new
WHERE device_sn = 'xxx'
AND dt >= 'xxx'
AND dt <= 'xxx'
ORDER BY dt DESC;
答案 0 :(得分:1)
处理 查询的最佳方法是使用
在未分区的表中INDEX(serial_number, dt)
更妙的是更改PRIMARY KEY
。假设您当前拥有id AUTO_INCREMENT
,因为没有适合作为“自然PK”的列的唯一组合,
PRIMARY KEY(serial_number, dt, id), -- to optimize that query
INDEX(id) -- to keep AUTO_INCREMENT happy
如果还有其他经常运行的查询,请提供它们;这可能会伤害他们。在大型表中,找到最佳索引是一项艰巨的任务。
其他评论:
serial_number
中拥有PRIMARY KEY
first ,所有引用单个序列号的查询都可能会受益。serial_numbers
?没问题。DELETEs
的成本比DROP PARTITION
高得多。这涉及PARTITION BY RANGE(TO_DAYS(dt))
。如果您对此感兴趣,我的PK建议仍然有效。 (有问题的查询在有或没有此分区的情况下都将以相同的速度运行。)DOUBLE
吗? FLOAT
的精度约为7个有效数字,仅占用4个字节。serial_number
是否固定为20个字符?如果不是,请使用VARCHAR
。另外,CHARACTER SET ascii
可能比utf8的默认值更好? 答案 1 :(得分:0)
解决查询
PRIMARY KEY (`id`),
KEY `device_sn_2` (`dt`,`device_sn`),
KEY `dt` (`dt`),
KEY `data` (`data`) USING BTREE,
KEY `test_udp_new_device_sn_dt_index` (`device_sn`,`dt`),
KEY `test_udp_new_device_sn_data_dt_index` (`device_sn`,`data`,`dt`)
->
PRIMARY KEY(`device_sn`,`dt`, id),
INDEX(id)
KEY `dt_sn` (`dt`,`device_sn`),
KEY `data` (`data`) USING BTREE,
注意:
device_sn, dt
开始PK,您可以获得使用WHERE device_sn = .. AND dt BETWEEN ...
进行查询的聚类优势INDEX(id)
是为了让AUTO_INCREMENT
开心。INDEX(a,b)
时,INDEX(a)
是多余的。(20)
是没有意义的; id
最多将达到40亿。lng decimal(10,5)
-不需要在小数点后第5个小数位;只需要3或2。所以:lat decimal(7,5),
lng decimal(8,5)`。每行总共将节省3个字节。