Bad performance when get traits for event with mysql backend
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Panko |
New
|
Undecided
|
Unassigned |
Bug Description
I'm using Queens version panko. And as it's deployed by kolla, panko_api is running in container.
# rpm -qa | grep panko
python-
openstack-
openstack-
I found get events from Panko with rest API is very slow.
And after research, the issue is narrow down to below part of source code.
https:/
Almost all time is consumed by trait_q.
```
for id_, key, t_date, t_int, t_float, t_text in (
if t_int is not None:
```
Below is the Request I used.
```
{
"q": [
{
"type": "string",
},
{
"type": "string",
"op": "le"
},
{
"type": "string",
"op": "ge"
}
]
}
```
When I call get API with above request, it returned in around 7s.
I added some logs to analyze this problem, as you can see from below log.
As you can see, almost all time is consumed when get traits for events.
2019-04-19 07:23:11.368 17 INFO panko.storage.
2019-04-19 07:23:11.370 17 INFO panko.storage.
2019-04-19 07:23:11.540 17 INFO panko.storage.
**2019-04-19 07:23:11.550 17 INFO panko.storage.
**2019-04-19 07:23:17.240 17 INFO panko.storage.
2019-04-19 07:23:17.241 17 INFO panko.storage.
I'm not sure if there's ant methods can be used the improve the performance.
Or it's just a bug, because the time is almost same no matter I get ten events or hundred events at once.
Hi there -
SQLAlchemy maintainer here. We are seeing extremely slow performance in this same area, such that the MySQL query times out and the service fails. Additionally, it pushed the CPU use of MySQL to 100% per cpu which is something I've never seen before. If the MySQL backend is recommended for use then I would think this should be high priority for this backend as it is a blocking issue when it causes MySQL itself to lose its ability to respond to other queries.
The reason seems to be that the query is too complicated and needs to be rewritten, most likely as a series of smaller and simpler queries. It has lots of deep nesting, subquery correlation, and UNIONs, enough so that it can cause MySQL to grind to a halt, making this more of a blocker. The code at https:/ /github. com/openstack/ panko/blob/ 7fe341001cb3132 389d62c99d5bc8a 790c366958/ panko/storage/ impl_sqlalchemy .py#L345 is explicit in it's request for this level of nesting and complexity so this is the area that would need to be reworked somehow.
Here's a full dump of the SQL we've observed, which I've formatted for readability:
SELECT trait_datetime_ event_id AS anon_1_ trait_datetime_ event_id, anon_1. trait_datetime_ key AS anon_1_ trait_datetime_ key, trait_datetime_ value AS anon_1_ trait_datetime_ value, anon_1.anon_2 AS anon_1_anon_2, event_id AS trait_datetime_ event_id, trait_datetime. `key` AS trait_datetime_key, datetime. value AS trait_datetime_ value, trait_text_ event_id AS trait_text_event_id trait_text_ event_id) event_id = anon_5.id int.event_ id AS trait_int_event_id, trait_int.`key` AS trait_int_key, trait_text_ event_id AS tra...
anon_1.
anon_1.
anon_1.anon_3 AS anon_1_anon_3, anon_1.anon_4 AS anon_1_anon_4
FROM (
SELECT trait_datetime.
trait_
CAST(NULL AS SIGNED INTEGER) AS anon_2, NULL AS anon_3, CAST(NULL AS CHAR(255)) AS anon_4 FROM trait_datetime
WHERE EXISTS (
SELECT * FROM (
SELECT event.id AS id FROM event INNER JOIN event_type ON event_type.id = event.event_type_id
WHERE (
EXISTS (
SELECT * FROM (
SELECT anon_7.
FROM (
SELECT trait_text.event_id AS trait_text_event_id FROM trait_text
WHERE NOT (
EXISTS (
SELECT * FROM (
SELECT trait_text.event_id AS event_id FROM trait_text
WHERE trait_text.`key` = %(key_1)s
) AS anon_8
WHERE trait_text.event_id = anon_8.event_id
)
)
UNION
SELECT trait_text.event_id AS trait_text_event_id
FROM trait_text, event
WHERE trait_text.`key` = %(key_2)s AND trait_text.value = %(value_1)s AND event.id = trait_text.event_id
) AS anon_7
) AS anon_6
WHERE event.id = anon_6.
) AND event.`generated` >= %(generated_1)s
ORDER BY event.`generated` ASC, event.message_id ASC
LIMIT %(param_1)s
) AS anon_5
WHERE trait_datetime.
)
UNION ALL
SELECT
trait_
NULL AS anon_9, trait_int.value AS trait_int_value,
NULL AS anon_10, NULL AS anon_11 FROM trait_int
WHERE EXISTS (
SELECT * FROM (
SELECT event.id AS id FROM event
INNER JOIN event_type ON event_type.id = event.event_type_id
WHERE (
EXISTS (
SELECT * FROM (
SELECT anon_7.