优化和加速MySQL查询选择
我试图找出哪种方法是优化MySQL数据库上当前选择查询的最佳方法 我有两个关系为一对多的MySQL表。一个是优化和加速MySQL查询选择,mysql,select,query-optimization,rdbms,Mysql,Select,Query Optimization,Rdbms,我试图找出哪种方法是优化MySQL数据库上当前选择查询的最佳方法 我有两个关系为一对多的MySQL表。一个是user表,它包含唯一的用户列表,大约有22krows。一个是linedata表,该表包含每个用户的所有可能坐标,大约49000行 在这种情况下,我们可以假设两个表之间的外键是id值。对于用户表,id也是自动递增主键,而在linedata表中,它不是主键,因为同一用户可以有更多行 创建STMT结构 选择查询 例如,如果我为筛选单个用户添加了另一个WHERE条件,则选择查询将起作用。假设我只
user
表,它包含唯一的用户列表,大约有22krows。一个是linedata
表,该表包含每个用户的所有可能坐标,大约49000行
在这种情况下,我们可以假设两个表之间的外键是id
值。对于用户表,id也是自动递增主键,而在linedata表中,它不是主键,因为同一用户可以有更多行
创建STMT结构
选择查询
例如,如果我为筛选单个用户添加了另一个WHERE条件,则选择查询将起作用。假设我只想选择200用户,然后我得到了14秒的执行时间。如果我只选择第一批100个用户,大约7秒。但在只有datetime范围条件的情况下,加载似乎没有结束点。有什么建议吗
更新
在遵循Rick的建议之后,现在查询基准大约为14秒。下面的解释扩展的:
id,选择类型,表格,类型,可能的键,键,键长度,参考,行,过滤,额外
1,主,u,索引,主,主,4,空,21959100.00,空
1,PRIMARY,l,ref,id_timestamp_index,id_timestamp_index,4,u.id,14100.00,“使用索引条件”
2,“依赖子查询”,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,“未使用表”
我对表格的某些值做了一些更改:
其中,用户表中的id
可以与linedata表中的userId
连接。现在它们是整数了。我们将为用户表中的userId值设置字符串类型,因为它是一种长字符串标识符,如0000309ab2912b2fd34350d7e6c079846bb6c5e1f97d3ccb053d15061433e77a\u 0
因此,我们将在用户
和行数据
表中提供一个快速示例:
+-------+-----------+-----------+-------------------+--------+---+
| id | isActive | userId | name | gender |age|
+-------+-----------+-----------+-------------------+--------+---+
| 1 | 1 | x4by4d | john | m | 22|
| 2 | 1 | 3ub3ub | bob | m | 50|
+-------+-----------+-----------+-------------------+--------+---+
+-------+-----------+-----------+------+---+
| id | userId |timestamp | x | y |
+-------+-----------+-----------+------+----+
| 1 | 1 | somedate | 30 | 10 |
| 2 | 1 | somedate | 45 | 15 |
| 3 | 1 | somedate | 50 | 20 |
| 4 | 2 | somedate | 20 | 5 |
| 5 | 2 | somedate | 25 | 10 |
+-------+-----------+-----------+------+----+
我在linedata表中添加了一个由userId
和timestamp
值组成的复合索引
如果我添加一个由userId
+时间戳
组成的复合主键,而不是将linedata
表的ai id值作为主键,那么可能会发生这种情况?是否应该提高性能?在讨论性能之前,我需要帮助您修复几个错误
首先,'2018-02-28620:00:00.000Z'
在MySQL中不起作用。它必须是'2018-02-28 20:00:00.000'
,并且需要对时区采取措施
然后,不要“在函数中隐藏列”。也就是说,DATEDIFF(l.timestamp…
不能在timestamp
上使用任何索引
因此,与其
WHERE DATEDIFF(l.timestamp, '2018-02-28T20:00:00.000Z') >= 0
AND DATEDIFF(l.timestamp, '2018-11-20T09:20:08.218Z') <= 0
CREATE TABLE `linedata` (
`id` int(11) NOT NULL,
`userId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
...
你是说
CREATE TABLE `linedata` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- (the id for `linedata`)
`userId` int NOT NULL, -- to link to the other table
...
PRIMARY KEY(id)
...
然后,对于每个用户
,可能会有多个行
在那一点上,这个
JOIN linedata l ON u.id=l.id
变成
JOIN linedata l ON u.id=l.userid
现在,为了提高性能:linedata
需要索引(userid,timestamp)
——顺序如下
现在,考虑一下输出。您要求的行数最多为2200行,其中一列中可能有数百个“ts,x,y”串在一起。什么会收到这么多数据?它会窒息吗
而GROUP_CONCAT
的默认限制为1024字节。这将允许大约50分。如果一个“用户”在9天内可以超过50个点,在运行查询之前考虑增加<代码> GROPY-CONTATAXMAXYLIN 。
要使其工作得更快,请按以下方式重新编写:
SELECT u.id, u.isActive, u.userId, u.name, u.gender, u.age,
( SELECT GROUP_CONCAT(CONCAT_WS(', ',timestamp, x, y)
ORDER BY timestamp ASC
SEPARATOR '; ')
) as linedata_0
FROM user u
JOIN linedata l ON u.id = l.userid
WHERE l.timestamp >= '2018-02-28 20:00:00.000'
AND l.timestamp < '2018-11-20 09:20:08.218';
选择u.id、u.isActive、u.userId、u.name、u.gender、u.age、,
(选择GROUP_CONCAT(CONCAT_WS(',',时间戳,x,y)
按时间戳订购ASC
分隔符“;”)
)作为linedata_0
来自用户u
在u.id=l.userid上连接linedata l
其中l.timestamp>=“2018-02-28 20:00:00.000”
和l.时间戳<'2018-11-20 09:20:08.218';
还有一件事。您可能希望能够通过名称查找用户;因此,添加索引(名称)
噢,userID的VARCHAR(255)
到底是什么??ID通常是整数。这涵盖了我要建议的大部分内容。注意,我认为OP包括了它们精确的表结构,只是linedata
表中没有PK,而且id
列实际上包含与user
表中的id
列相同的值。出于某种目的,userId
看起来像一个替代标识符。很可能,您建议的(userid,timestamp)
索引可以通过将(id,timestamp)
生成主键来处理,因为不可能允许用户一次拥有多个位置。@WillemRenzema所说的是正确的。我没有表linedata的pk,但无论如何,我创建了一个名为id的ai pk。我将用户表的id(pk ai)与用户id值连接起来,该值现在也是整数,并且匹配正确。@Rick James感谢您的回答。我已经纠正了某些观点。。尤其是personId
类型。我现在已经生成了一个与user
表的唯一id
对应的整数值。我认为不能正常工作的是您的查询建议,因为我只得到一行结果,对应于一个用户。理论上,我应该得到大约21k行,每个时间戳和坐标的串联。我想你错过了u.id的最后一组。我说得对吗?如果我加上它,获取所有数据的基准大约是15秒。我更新了EXPLAIN
stmt.@UgoL-好的开始。但是b
CREATE TABLE `linedata` (
`id` int(11) NOT NULL AUTO_INCREMENT, -- (the id for `linedata`)
`userId` int NOT NULL, -- to link to the other table
...
PRIMARY KEY(id)
...
JOIN linedata l ON u.id=l.id
JOIN linedata l ON u.id=l.userid
SELECT u.id, u.isActive, u.userId, u.name, u.gender, u.age,
( SELECT GROUP_CONCAT(CONCAT_WS(', ',timestamp, x, y)
ORDER BY timestamp ASC
SEPARATOR '; ')
) as linedata_0
FROM user u
JOIN linedata l ON u.id = l.userid
WHERE l.timestamp >= '2018-02-28 20:00:00.000'
AND l.timestamp < '2018-11-20 09:20:08.218';