簡體   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