我试图找出哪种方法是优化mysql数据库上当前选择查询的最佳方法。
我有两个mysql表,它们的关系是一对多。一个是 user
表中包含唯一的用户列表,它有大约22个krows。一个是 linedata
包含每个用户的所有可能坐标的表,它有大约49000行。
在这种情况下,我们可以假设两个表之间的外键是 id
价值观。在用户表中,id也是自动递增的主键,而在linedata表中,它不是主键,因为我们可以为同一个用户拥有更多的行。
创建stmt结构
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`isActive` tinyint(4) NOT NULL,
`userId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`gender` varchar(45) COLLATE utf8_unicode_ci NOT NULL,
`age` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21938 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `linedata` (
`id` int(11) NOT NULL,
`userId` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`timestamp` datetime NOT NULL,
`x` float NOT NULL,
`y` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
选择查询
SELECT
u.id,
u.isActive,
u.userId,
u.name,
u.gender,
u.age,
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.id
WHERE DATEDIFF(l.timestamp, '2018-02-28T20:00:00.000Z') >= 0
AND DATEDIFF(l.timestamp, '2018-11-20T09:20:08.218Z') <= 0
GROUP BY userId;
解释输出
+-------+---------------+-----------+-----------+-------------------+-----------+---------------+-----------+-----------+------------------------------------------------------------+
| ID | SELECT_TYPE | TABLE | TYPE | POSSIBLE_KEYS | KEY | KEY_LEN | REF | ROWS | EXTRA |
+-------+---------------+-----------+-----------+-------------------+-----------+---------------+-----------+-----------+------------------------------------------------------------+
| 1 | SIMPLE | l | ALL | NULL | NULL | NULL | NULL | 491157 | "Using where; Using temporary; Using filesort" |
+-------+---------------+-----------+-----------+-------------------+-----------+---------------+-----------+-----------+------------------------------------------------------------+
| 1 | SIMPLE | u | eq_ref | PRIMARY | PRIMARY | 4 | l.id | 1 | NULL |
+-------+---------------+-----------+-----------+-------------------+-----------+---------------+-----------+-----------+------------------------------------------------------------+
例如,如果我为筛选单个用户添加另一个where条件,选择查询就可以工作。假设我只想选择200个用户,然后我得到大约14秒的执行时间。如果我只选择前100个用户,大约7秒。但是在只有datetime范围的情况下,它似乎没有结束点。有什么建议吗?
更新
在遵循rick的建议之后,现在查询基准大约是14秒。就在下面 EXPLAIN EXTENDED
:
id,select\ type,table,type,possible\ keys,key,key\ len,ref,rows,filtered,extra 1,primary,u,index,primary,primary,4,null,21959100.00,null 1,primary,l,ref,id\ timestamp\ index,id\ timestamp\ index,4,u.id,14100.00,“使用索引条件”2,“依赖子查询”,null,null,null,null,null,null,null,“未使用表”
我改变了一些表的值:
在哪里 id
在用户表中可以与 userId
在linedata表中。现在它们是整数了。我们将为用户表中的userid值设置字符串类型,因为它是一种长字符串标识符,如0000309ab2912b2fd34350d7e6c079846bb6c5e1f97d3ccb053d15061433e77a\0。
所以,我们来举个例子 user
而且在 linedata
表格:
+-------+-----------+-----------+-------------------+--------+---+
| 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 |
+-------+-----------+-----------+------+----+
我添加了一个由 userId
以及 timestamp
linedata表中的值。
也许不是把ai id值作为主键 linedata
表中,如果添加由 userId
+ timestamp
? 是否应该提高性能?
1条答案
按热度按时间qxgroojn1#
在讨论性能之前,我需要帮助您修复几个bug。
首先,
'2018-02-28T20:00:00.000Z'
在mysql中不起作用。必须是这样'2018-02-28 20:00:00.000'
需要对时区做些什么。然后,不要“在函数中隐藏列”。就是这样
DATEDIFF(l.timestamp ...)
无法在上使用任何索引timestamp
.所以
像这样做
我对这两张table感到困惑。两者都有
id
以及userid
但你还是加入了id
. 也许不是你是说
那么可能有几个
linedata
每行user
.在那一点上,这个
变成
现在,为了性能:
linedata
需要INDEX(userid, timestamp)
-按这个顺序。现在,考虑一下输出。您要求最多22k行,其中一列中可能有数百个“ts,x,y”串在一起。什么会收到这么多数据?它会窒息吗?
以及
GROUP_CONCAT
默认限制为1024字节。这样可以得到大约50分。如果一个“用户”可以在9天内超过50个点,考虑增加group_concat_max_len
在运行查询之前。要使其工作得更快,请按以下方式重新编写:
另一件事。您可能希望能够通过
name
; 所以加上INDEX(name)
哦,这到底是怎么回事VARCHAR(255)
为了userID
?? ID通常是整数。