MySQL:使用内部连接的慢速分组

MySQL:使用内部连接的慢速分组,mysql,database,performance,Mysql,Database,Performance,我有两张桌子要加入 表1:botika\u帮助台\u票据 创建表'botika\u帮助台\u票据'( `票证idx`int(11)非空自动增量, `票证id`varchar(150)默认为空, `bot_id`varchar(150)默认为空, `用户_id`varchar(150)默认为空, `票证状态'varchar(60)默认为空, `票证id`varchar(150)默认为空, `chat\u log\u id\u start`varchar(150)默认为空, `chat_log_id

我有两张桌子要加入

表1:
botika\u帮助台\u票据

创建表'botika\u帮助台\u票据'(
`票证idx`int(11)非空自动增量,
`票证id`varchar(150)默认为空,
`bot_id`varchar(150)默认为空,
`用户_id`varchar(150)默认为空,
`票证状态'varchar(60)默认为空,
`票证id`varchar(150)默认为空,
`chat\u log\u id\u start`varchar(150)默认为空,
`chat_log_id_end`varchar(150)默认为空,
`chat_id`varchar(150)不为空,
`创建日期`日期时间默认为空,
`票证号码'varchar(50)默认为空,
`票证组'varchar(300)默认为空,
`附加信息'varchar(600)默认为空,
`票证优先级'varchar(20)默认为空,
`票证类别'varchar(50)默认为空,
`部门id`varchar(50)默认为空,
`department_idx`int(11)默认为空,
`工作区_id`varchar(50)默认为空,
`工作区_idx`int(11)默认为空,
主键(`ticket_idx`),
键“用户id”(“用户id”),
键'bot\u id'('bot\u id'),
键'comp_1'('chat_log_id_start','chat_log_id_end'),
键“workspace\u id”(“workspace\u id”),
键“创建日期”(“创建日期”),
输入“idx\U botika\U帮助台\U票证\U票证\U idx”(“票证\U idx”),
键'chat\u id'('chat\u id'),
键'ticket\u id'('ticket\u id`)
)ENGINE=InnoDB AUTO_INCREMENT=604745默认字符集=latin1;
表2:
botika\u聊天记录

创建表'botika\u聊天记录'(
`chat_log_idx`int(11)非空自动增量,
`聊天日志id`varchar(50)非空默认值'0',
`bot_id`varchar(50)默认为空,
`用户_id`varchar(150)默认为空,
`消息“mediumtext,
`创建日期`日期时间默认为空,
`来自'varchar(10)的消息不为空,
`chat_type`varchar(20)不为空,
`聊天室状态'varchar(20)不为空,
`chat_id`varchar(150)不为空,
`消息_id`varchar(100)默认为空,
`message_timestamp`varchar(50)默认为空,
`消息_status`varchar(50)默认为空,
`消息\u last\u update`datetime默认值为空,
`广播id`varchar(50)默认为空,
主键(`chat\u log\u idx`),
键“用户id”(“用户id”),
键'bot\u id'('bot\u id'),
输入'message\u from'('message\u from'),
键“创建日期”(“创建日期”),
键'chat\u log\u id'('chat\u log\u id'),
键`message\u last\u update`(`message\u last\u update`),
键'message\u id'('message\u id'),
键“chat\u type”(“chat\u type”),
键'chat\u id'('chat\u id`)
)ENGINE=InnoDB AUTO_INCREMENT=14852380默认字符集=1;
我在
botika\u帮助台\u记录中有大约8万行,在
botika\u聊天\u日志中有1.6万行

运行此查询

选择
聊天类型,计数(票证id)为总票证
从…起
botika_帮助台_票作为ht
内连接
botika_chat_在cl.chat_id=ht.chat_id上作为cl记录
按聊天室类型分组;
需要很长时间。这需要10多分钟。我花了很长时间才看到结果,因为我总是停止执行

EXPLAIN
给了我这个

+----+-------------+-------+------------+-------+-------------------+---------+---------+------------------------+-------+----------+------------------------------+
| id | select_type | table | partitions | type  | possible_keys     | key     | key_len | ref                    | rows  | filtered | Extra                        |
+----+-------------+-------+------------+-------+-------------------+---------+---------+------------------------+-------+----------+------------------------------+
|  1 | SIMPLE      | ht    | NULL       | index | chat_id           | chat_id | 152     | NULL                   | 15870 |   100.00 | Using index; Using temporary |
|  1 | SIMPLE      | cl    | NULL       | ref   | chat_type,chat_id | chat_id | 152     | botmasterdb.ht.chat_id |  1838 |   100.00 | NULL                         |
+----+-------------+-------+------------+-------+-------------------+---------+---------+------------------------+-------+----------+------------------------------+
在没有连接的情况下单独运行此查询非常快,0.04秒

选择
聊天室类型
从…起
botika_聊天记录
按聊天室类型分组;

我之所以加入这两个表,是为了计算每种
聊天类型的票证数量

我不确定您为什么创建了这么多索引。我的建议是根据你的业务分析和减少你的指数

以下是如何在此线程中优化查询。Mysql版本在我的验证沙箱中是
5.7.31

  • botika\u聊天记录上添加组合索引
    表格:
  • botika\u帮助台\u票据
    表中添加组合索引
  • 将查询更改为:
  • 解释结果如下:

    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    | id | select_type | table | partitions | type  | possible_keys           | key                     | key_len | ref             | rows | filtered | Extra       |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    |  1 | SIMPLE      | cl    | NULL       | index | idx_type_id             | idx_type_id             | 174     | NULL            |    1 |   100.00 | Using index |
    |  1 | SIMPLE      | ht    | NULL       | ref   | index_chat_id_ticket_id | index_chat_id_ticket_id | 152     | test.cl.chat_id |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    
    驾驶台的选择需要考虑很多因素。桌子尺寸, 列值的基数以及其他因素都会影响选择 指驾驶台(如:提示)。有关如何选择的更多详细信息 驾驶台,请参阅

    但是,当我使用不同的连接顺序测试上面的查询时,执行计划的结果是不同的。我认为这可能是由于我自己的沙箱中没有数据造成的。 执行计划如下。这就是为什么我仍然在第3步中向您提供该查询

    mysql> explain SELECT
        ->     chat_type, COUNT(ticket_id) AS total_tickets
        -> FROM
        ->     botika_helpdesk_tickets AS ht
        ->         INNER JOIN
        ->     botika_chat_logs AS cl ON cl.chat_id = ht.chat_id
        -> GROUP BY chat_type;
    ERROR 2006 (HY000): MySQL server has gone away
    No connection. Trying to reconnect...
    Connection id:    24
    Current database: test
    
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    | id | select_type | table | partitions | type | possible_keys                 | key     | key_len | ref             | rows | filtered | Extra                           |
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    |  1 | SIMPLE      | ht    | NULL       | ALL  | chat_id                       | NULL    | NULL    | NULL            |    1 |   100.00 | Using temporary; Using filesort |
    |  1 | SIMPLE      | cl    | NULL       | ref  | chat_type,chat_id,idx_id_type | chat_id | 152     | test.ht.chat_id |    1 |   100.00 | NULL                            |
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    2 rows in set, 1 warning (0.01 sec)
    
    表中的
    表大小
    列值基数
    和索引必须与我的沙箱中的不同。确保检查沙箱上的执行计划。


    添加这些索引后,为什么查询会更快:

  • botika\u聊天记录
    的记录少于
    botika\u帮助台\u记录
    。如果驾驶台是
    botika\u chat\u log
    ,性能会更好
  • Index
    Index\u chat\u id\u ticket\u id
    是一个包含ticket\u id和chat\u id的
    索引,在计算ticket\u id时,mysql不需要返回主索引
  • 新创建的索引
    idx\u type\u id
    是一个覆盖
    的索引,这将使查询具有更好的性能
  • 按聊天类型分组也将从新创建的索引中受益

  • 还有。。。你说的是
    COUNT(ticket\u id)
    而不是
    COUNT(*)
    。这将强制执行检查每个
    票证id
    是否为
    非NULL
    。我怀疑这是过度杀戮。执行以下部分或全部操作:

    • 勾选的\u id
      (以及许多其他列)的定义更改为
      非空
      ,如果合适
    • 更改为
      COUNT(*)
    • 添加已建议的索引:
      索引(聊天室id、票证id)

    很抱歉,我应该在查询中添加
    COUNT
    。编辑。嗯,看起来都不错。我不禁想知道这里是否有腐败的东西。我创建了一个DB FIDLE,但没有得到相同的查询计划。()
    SELECT
        chat_type, COUNT(ticket_id) AS total_tickets
    FROM
        botika_chat_logs AS cl
            INNER JOIN
        botika_helpdesk_tickets AS ht ON cl.chat_id = ht.chat_id
    GROUP BY chat_type;
    
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    | id | select_type | table | partitions | type  | possible_keys           | key                     | key_len | ref             | rows | filtered | Extra       |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    |  1 | SIMPLE      | cl    | NULL       | index | idx_type_id             | idx_type_id             | 174     | NULL            |    1 |   100.00 | Using index |
    |  1 | SIMPLE      | ht    | NULL       | ref   | index_chat_id_ticket_id | index_chat_id_ticket_id | 152     | test.cl.chat_id |    1 |   100.00 | Using index |
    +----+-------------+-------+------------+-------+-------------------------+-------------------------+---------+-----------------+------+----------+-------------+
    
    mysql> explain SELECT
        ->     chat_type, COUNT(ticket_id) AS total_tickets
        -> FROM
        ->     botika_helpdesk_tickets AS ht
        ->         INNER JOIN
        ->     botika_chat_logs AS cl ON cl.chat_id = ht.chat_id
        -> GROUP BY chat_type;
    ERROR 2006 (HY000): MySQL server has gone away
    No connection. Trying to reconnect...
    Connection id:    24
    Current database: test
    
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    | id | select_type | table | partitions | type | possible_keys                 | key     | key_len | ref             | rows | filtered | Extra                           |
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    |  1 | SIMPLE      | ht    | NULL       | ALL  | chat_id                       | NULL    | NULL    | NULL            |    1 |   100.00 | Using temporary; Using filesort |
    |  1 | SIMPLE      | cl    | NULL       | ref  | chat_type,chat_id,idx_id_type | chat_id | 152     | test.ht.chat_id |    1 |   100.00 | NULL                            |
    +----+-------------+-------+------------+------+-------------------------------+---------+---------+-----------------+------+----------+---------------------------------+
    2 rows in set, 1 warning (0.01 sec)