优化并加速mysql查询选择

cnh2zyt3  于 2021-06-19  发布在  Mysql
关注(0)|答案(1)|浏览(296)

我试图找出哪种方法是优化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 ? 是否应该提高性能?

qxgroojn

qxgroojn1#

在讨论性能之前,我需要帮助您修复几个bug。
首先, '2018-02-28T20: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

像这样做

WHERE  l.timestamp >= '2018-02-28 20:00:00.000'
      AND  l.timestamp  < '2018-11-20 09:20:08.218'

我对这两张table感到困惑。两者都有 id 以及 userid 但你还是加入了 id . 也许不是

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)
...

那么可能有几个 linedata 每行 user .
在那一点上,这个

JOIN  linedata l  ON u.id=l.id

变成

JOIN  linedata l  ON u.id=l.userid

现在,为了性能: linedata 需要 INDEX(userid, timestamp) -按这个顺序。
现在,考虑一下输出。您要求最多22k行,其中一列中可能有数百个“ts,x,y”串在一起。什么会收到这么多数据?它会窒息吗?
以及 GROUP_CONCAT 默认限制为1024字节。这样可以得到大约50分。如果一个“用户”可以在9天内超过50个点,考虑增加 group_concat_max_len 在运行查询之前。
要使其工作得更快,请按以下方式重新编写:

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';

另一件事。您可能希望能够通过 name ; 所以加上 INDEX(name) 哦,这到底是怎么回事 VARCHAR(255) 为了 userID ?? ID通常是整数。

相关问题