繁体   English   中英

如果我不能进行索引和分区,如何使这个 MySQL 查询工作得更快?

[英]How to make this MySQL query work faster if I can not do indexing and partition?

我正在围绕 Zabbix MySQL (MariaDB) 数据库构建 web 应用程序。

我需要显示包含所有主机名和主机当前问题列表的表格,我执行以下 sql 查询(在一个 http GET 请求期间,我执行 7 个这样的 sql 查询,具有不同的 events.name 值以检查所有可能的问题)这样做:

SELECT distinct(hosts.hostid), max(CONVERT(CONCAT(events.eventid, events.value, events.severity), UNSIGNED))
FROM hosts
INNER JOIN hosts_groups ON hosts.hostid = hosts_groups.hostid
INNER JOIN hstgrp ON hosts_groups.groupid = hstgrp.groupid

INNER JOIN items ON hosts.hostid = items.hostid
INNER JOIN functions ON items.itemid = functions.itemid
INNER JOIN events ON functions.triggerid = events.objectid
WHERE events.name = %s
AND hstgrp.groupid = %s
AND hosts.status != 3 # 3 - not templates
GROUP BY hosts.hostid;

sql 查询的总时间在 20 秒到 120 秒之间,我认为这个问题与事件表的大小以及新事件添加到表中的速度非常快有关。

EXPLAIN命令的结果: 在此处输入图像描述

我想我可以尝试对 events.name 列进行索引,但恐怕这对 Zabbix 应用程序来说可能是负面因素。 另一种选择是分区,但 Zabbix 有自己的分区 howto 计划,所以我也不敢这样做。

我还有哪些其他选择可以使查询工作更快,查询时间差异如此之大(最多 6-7 倍)的原因是什么?

编辑:

如果我限制事件的时间,例如最多 10 天,查询工作得更快,但我丢失了一些事件,因为错误事件可能发生在 1 个月前,并且当时从未得到解决。

SELECT hosts.hostid, max(CONVERT(CONCAT(events.eventid, events.value, events.severity), UNSIGNED))
FROM hosts
INNER JOIN hosts_groups ON hosts.hostid = hosts_groups.hostid
INNER JOIN hstgrp ON hosts_groups.groupid = hstgrp.groupid

INNER JOIN items ON hosts.hostid = items.hostid
INNER JOIN functions ON items.itemid = functions.itemid
INNER JOIN events ON functions.triggerid = events.objectid
WHERE events.eventid >= (select eventid from events  where events.clock >= 1602773508 limit 1) AND events.name = "Устройство недоступно"
AND hstgrp.groupid = 15
AND hosts.status != 3 # 3 - not templates
GROUP BY hosts.hostid;

编辑

问题表的结果与事件表的结果相矛盾,称为不可达表的主机可以通过 ping 获得,并且在 zabbix intereface 中未标记为不可达,查询:

SELECT distinct(hosts.hostid) FROM hosts
INNER JOIN hosts_groups ON hosts.hostid = hosts_groups.hostid
INNER JOIN hstgrp ON hosts_groups.groupid = hstgrp.groupid

INNER JOIN items ON hosts.hostid = items.hostid
INNER JOIN functions ON items.itemid = functions.itemid
INNER JOIN problem ON functions.triggerid = problem.objectid
WHERE problem.name = "Device is unreachable"
AND hstgrp.groupid = 15
AND hosts.status != 3 ;

此外,我发现对于一台主机,存在多个名称相同但时间(时钟)不同的问题,尽管我预计具体主机的指定名称最多会出现一个问题:

SELECT hosts.hostid, problem.name, problem.clock FROM hosts
INNER JOIN hosts_groups ON hosts.hostid = hosts_groups.hostid
INNER JOIN hstgrp ON hosts_groups.groupid = hstgrp.groupid

INNER JOIN items ON hosts.hostid = items.hostid
INNER JOIN functions ON items.itemid = functions.itemid
INNER JOIN problem ON functions.triggerid = problem.objectid
WHERE problem.name = "Device is unreachable"
AND hstgrp.groupid = 15
AND hosts.status != 3 ;

问题表中一台主机的结果:

10398 设备无法访问 1603625463 10398 设备无法访问 1603630863 10398 设备无法访问 1603661463 10398 设备无法访问 1603679463 10398 设备无法访问 1603697463

从评论中回答“建造”。

虽然最好的做法是使用problem.get API,但您可以从文档中推断problem表的工作原理并将其用于 SQL 查询:

此方法用于检索未解决的问题。 如果指定,也可以额外检索最近解决的问题。 确定“最近”年龄的时间段在管理 → 常规中定义。

在此之前解决的问题不会保留在问题表中。 要检索过去更早解决的问题,请使用 event.get 方法。

您应该加入该表而不是events表,该表包含过去发生的所有事件。

如果您不能在 events.name 或 hstgrp.groupid 上创建索引,那您就不走运了。 如果您在 events.name 上已有索引,请尝试使用索引提示强制使用该索引,例如JOIN events FORCE INDEX (index_name) 您可能还必须重新安排 JOIN 顺序以将事件表放在前面并使用 STRAIGHT_JOIN 来防止优化重新排序连接。 如果它没有帮助(或使事情变得更糟),那么就没有什么可以做的了。

编辑:试试这个:

将 events(objectid) 上的索引扩展到 events(objectid, name) 并将查询更改为:

SELECT distinct(hosts.hostid), 
max(CONVERT(CONCAT(events.eventid, events.value, 
events.severity), UNSIGNED))
FROM hosts
INNER JOIN hosts_groups ON hosts.hostid = hosts_groups.hostid
INNER JOIN hstgrp ON hosts_groups.groupid = hstgrp.groupid 
INNER JOIN items ON hosts.hostid = items.hostid
INNER JOIN functions ON items.itemid = functions.itemid
INNER JOIN events ON functions.triggerid = events.objectid AND events.name = %s
WHERE hstgrp.groupid = %s
AND hosts.status != 3 # 3 - not templates
GROUP BY hosts.hostid;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM