MySQL:使用内部连接的慢速分组
我有两张桌子要加入 表1: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
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
,性能会更好
IndexIndex\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)