简体   繁体   English

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

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

I am building web application around Zabbix MySQL (MariaDB) database.我正在围绕 Zabbix MySQL (MariaDB) 数据库构建 web 应用程序。

I need to display table with all hostnames and list of current problems for the hosts, I do the following sql query (during one http GET request I do 7 such sql queries with different events.name values to check all possible problem) to do so:我需要显示包含所有主机名和主机当前问题列表的表格,我执行以下 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;

The sum time of the sql queries can range from 20 seconds to 120 seconds, I suppose that the issue is related to the size of events table and the fact that new events are added to the table really fast. sql 查询的总时间在 20 秒到 120 秒之间,我认为这个问题与事件表的大小以及新事件添加到表中的速度非常快有关。

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

I suppose that I can try to do indexing of events.name column, but I am afraid that it can be negative factor for Zabbix application.我想我可以尝试对 events.name 列进行索引,但恐怕这对 Zabbix 应用程序来说可能是负面因素。 Another option is partition but Zabbix have its' own partition howto plan, so I afraid to do it too.另一种选择是分区,但 Zabbix 有自己的分区 howto 计划,所以我也不敢这样做。

What other options do I have to make the query work faster and what can be the reason of such a great difference in the query time (up to 6-7 times)?我还有哪些其他选择可以使查询工作更快,查询时间差异如此之大(最多 6-7 倍)的原因是什么?

EDIT:编辑:

If I restrict time of events eg up to 10 last days, the queries work faster, but I loose some of events, since error event could take place 1 month ago and never was not solved then.如果我限制事件的时间,例如最多 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;

EDIT编辑

The results from problem table contradict to results from events table, hosts which are called not reachable table are available by ping and not marked as not reachable in zabbix intereface, query:问题表的结果与事件表的结果相矛盾,称为不可达表的主机可以通过 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 ;

In addition I found that for one host there are several problems with the same name but different time (clock), though I expected maximum one problem with the specified name for the concrete host:此外,我发现对于一台主机,存在多个名称相同但时间(时钟)不同的问题,尽管我预计具体主机的指定名称最多会出现一个问题:

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 ;

Results for one host from problems table:问题表中一台主机的结果:

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

Answer "built" from the comments.从评论中回答“建造”。

While the best course of action is to use the problem.get API, from the documentation you can infer how the problem table works and use it for a SQL query:虽然最好的做法是使用problem.get API,但您可以从文档中推断problem表的工作原理并将其用于 SQL 查询:

This method is for retrieving unresolved problems.此方法用于检索未解决的问题。 It is also possible, if specified, to additionally retrieve recently resolved problems.如果指定,也可以额外检索最近解决的问题。 The period that determines how old is “recently” is defined in Administration → General.确定“最近”年龄的时间段在管理 → 常规中定义。

Problems that were resolved prior to that period are not kept in the problem table.在此之前解决的问题不会保留在问题表中。 To retrieve problems that were resolved further back in the past, use the event.get method.要检索过去更早解决的问题,请使用 event.get 方法。

You should join that table and not the events table, which contains every event that happened in the past.您应该加入该表而不是events表,该表包含过去发生的所有事件。

If you cannot create an index on events.name or hstgrp.groupid you are out of luck.如果您不能在 events.name 或 hstgrp.groupid 上创建索引,那您就不走运了。 If you already have an index on events.name, try forcing the use of that index using an index hint, eg JOIN events FORCE INDEX (index_name) .如果您在 events.name 上已有索引,请尝试使用索引提示强制使用该索引,例如JOIN events FORCE INDEX (index_name) You may also have to re-arrange the JOIN order to put the events table at the front and use a STRAIGHT_JOIN to prevent the optimized from reordering the join.您可能还必须重新安排 JOIN 顺序以将事件表放在前面并使用 STRAIGHT_JOIN 来防止优化重新排序连接。 If it doesn't help (or it makes things worse), there is not much else that can be done.如果它没有帮助(或使事情变得更糟),那么就没有什么可以做的了。

Edit: Try this:编辑:试试这个:

Extend the index on events(objectid) to events(objectid, name) and change the query to:将 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