Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Queries against Large Numbers of Annotations can overload/lock MySQL #21902

Closed
3 tasks
kylebrandt opened this issue Feb 3, 2020 · 4 comments · Fixed by #21915
Closed
3 tasks

Queries against Large Numbers of Annotations can overload/lock MySQL #21902

kylebrandt opened this issue Feb 3, 2020 · 4 comments · Fixed by #21915
Assignees
Labels
area/annotations area/backend/db/mysql area/backend/db area/backend prio/critical Highest priority. Must be actively worked on as someone's top priority right now.
Milestone

Comments

@kylebrandt
Copy link
Contributor

kylebrandt commented Feb 3, 2020

What happened:

MySQL database locks up on Annotation query when there are a large (millions) of annotation rows. Grafana-Server subsequently fails as it loses access to its database.

What you expected to happen:

Queries that don't have to scan the entire table, and lock up the db.

How to reproduce it (as minimally and precisely as possible):

Unhappy Query:

MySQL [hg_redacted]> select id,text from annotation where org_id=1 and epoch<=unix_timestamp(now())*1000 and epoch_end>=unix_timestamp(now())*1000-60*10
^CCtrl-C -- query killed. Continuing normally.
ERROR 1317 (70100): Query execution was interrupted
MySQL [hg_redacted]> explain select id,text from annotation where org_id=1 and epoch<=unix_timestamp(now())*1000 and epoch_end>=unix_timestamp(now())*10
+----+-------------+------------+------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+---------+-------+---------+--
| id | select_type | table      | partitions | type | possible_keys                                                                                                                                                                                 | key                            | key_len | ref   | rows    | f
+----+-------------+------------+------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+---------+-------+---------+--
|  1 | SIMPLE      | annotation | NULL       | ref  | IDX_annotation_org_id_alert_id,IDX_annotation_org_id_type,IDX_annotation_org_id_dashboard_id_panel_itation_org_id_created,IDX_annotation_org_id_updated,IDX_annotation_org_id_epoch_epoch_end | IDX_annotation_org_id_alert_id | 8       | const | 2102754 |
+----+-------------+------------+------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+--------------------------------+---------+-------+---------+--
1 row in set, 1 warning (0.037 sec)

MySQL [hg_redacted]> explain select id,text from annotation where org_id=1 and epoch<=unix_timestamp(now())*1000 and epoch_end>=unix_timestamp(now())*10
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: annotation
   partitions: NULL
         type: ref
possible_keys: IDX_annotation_org_id_alert_id,IDX_annotation_org_id_type,IDX_annotation_org_id_dashboard_id_panel_id_epoch,IDX_annotation_org_id_epoch,IDX
          key: IDX_annotation_org_id_alert_id
      key_len: 8
          ref: const
         rows: 2102754
     filtered: 11.11
        Extra: Using where
1 row in set, 1 warning (0.002 sec)

MySQL [hg_redacted]> show create table annotation;
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Table      | Create Table                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| annotation | CREATE TABLE `annotation` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `org_id` bigint(20) NOT NULL,
  `alert_id` bigint(20) DEFAULT NULL,
  `user_id` bigint(20) DEFAULT NULL,
  `dashboard_id` bigint(20) DEFAULT NULL,
  `panel_id` bigint(20) DEFAULT NULL,
  `category_id` bigint(20) DEFAULT NULL,
  `type` varchar(25) COLLATE utf8mb4_unicode_ci NOT NULL,
  `title` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `text` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `metric` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `prev_state` varchar(25) COLLATE utf8mb4_unicode_ci NOT NULL,
  `new_state` varchar(25) COLLATE utf8mb4_unicode_ci NOT NULL,
  `data` text COLLATE utf8mb4_unicode_ci NOT NULL,
  `epoch` bigint(20) NOT NULL,
  `region_id` bigint(20) DEFAULT '0',
  `tags` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `created` bigint(20) DEFAULT '0',
  `updated` bigint(20) DEFAULT '0',
  `epoch_end` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `IDX_annotation_org_id_alert_id` (`org_id`,`alert_id`),
  KEY `IDX_annotation_org_id_type` (`org_id`,`type`),
  KEY `IDX_annotation_org_id_dashboard_id_panel_id_epoch` (`org_id`,`dashboard_id`,`panel_id`,`epoch`),
  KEY `IDX_annotation_org_id_epoch` (`org_id`,`epoch`),
  KEY `IDX_annotation_org_id_created` (`org_id`,`created`),
  KEY `IDX_annotation_org_id_updated` (`org_id`,`updated`),
  KEY `IDX_annotation_org_id_epoch_epoch_end` (`org_id`,`epoch`,`epoch_end`)
) ENGINE=InnoDB AUTO_INCREMENT=12444472 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci |

Environment:

Introduced I think in 6.4.x by #17673

TODO:

@kylebrandt kylebrandt added prio/critical Highest priority. Must be actively worked on as someone's top priority right now. area/annotations area/backend/db area/backend area/backend/db/mysql labels Feb 3, 2020
@kylebrandt kylebrandt added this to the 6.6.1 milestone Feb 3, 2020
@kylebrandt kylebrandt self-assigned this Feb 3, 2020
@kylebrandt
Copy link
Contributor Author

Note from @DanCech :

"It occurs to me that given our usual query patterns ask for data near the current time, an index on org_id, epoch_end would likely be much more efficient for the majority of queries as it'll cut down the number of rows very quickly. Unsure whether org_id, epoch_end, epoch would be worth the overhead, but the main thing is that epoch_end is the useful column for cutting out the majority of rows"

@kylebrandt
Copy link
Contributor Author

kylebrandt commented Feb 3, 2020

Still populating my local instance with annotations (following is ~10k), but using Dan's suggestion, which I took as:

DROP INDEX IDX_annotation_org_id_epoch ON annotation;
DROP index IDX_annotation_org_id_epoch_epoch_end ON annotation;
ALTER TABLE annotation ADD INDEX IDX_annotation_org_id_epoch_end (`org_id` , `epoch_end`) ;

Seems to do better:

mysql> explain select id,text from annotation where org_id=1 and epoch<=unix_timestamp(now())*1000 and epoch_end>=unix_timestamp(now())*1000-60*10\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: annotation
         type: range
possible_keys: IDX_annotation_org_id_alert_id,IDX_annotation_org_id_type,IDX_annotation_org_id_dashboard_id_panel_id_epoch,IDX_annotation_org_id_created,IDX_annotation_org_id_updated,IDX_annotation_org_id_epoch_end
          key: IDX_annotation_org_id_epoch_end
      key_len: 16
          ref: NULL
         rows: 6
        Extra: Using index condition; Using where
1 row in set (0.00 sec)

@marefr
Copy link
Member

marefr commented Feb 4, 2020

Note from @DanCech :

"It occurs to me that given our usual query patterns ask for data near the current time, an index on org_id, epoch_end would likely be much more efficient for the majority of queries as it'll cut down the number of rows very quickly. Unsure whether org_id, epoch_end, epoch would be worth the overhead, but the main thing is that epoch_end is the useful column for cutting out the majority of rows"

We need both because when using absolute time range in dashboard we only want to get the annotations in that range.

@DanCech
Copy link
Collaborator

DanCech commented Feb 4, 2020

Note from @DanCech :
"It occurs to me that given our usual query patterns ask for data near the current time, an index on org_id, epoch_end would likely be much more efficient for the majority of queries as it'll cut down the number of rows very quickly. Unsure whether org_id, epoch_end, epoch would be worth the overhead, but the main thing is that epoch_end is the useful column for cutting out the majority of rows"

We need both because when using absolute time range in dashboard we only want to get the annotations in that range.

I'm talking about indexes, not queries. We definitely need both parameters in the query, the point is that if the index order is org_id, epoch, epoch_end the index will likely be less efficient than if it were org_id, epoch_end, epoch for the majority of our queries (which occur near the current time) because it will cut down the list of candidate rows faster.

I'm not sure whether there is a benefit to having org_id, epoch_end, epoch vs just org_id, epoch_end, there is a cost to indexing additional fields and we may be just as well off using the rows themselves for the epoch condition.

marefr added a commit that referenced this issue Feb 5, 2020
…rove database query performance (#21915)

Drop indices and create new ones and rewrites annotation find query 
to address performance issues when querying annotation table and 
there is a large amount of rows.

Fixes #21902

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Kyle Brandt <kyle@kbrandt.com>
alexanderzobnin pushed a commit that referenced this issue Feb 6, 2020
…rove database query performance (#21915)

Drop indices and create new ones and rewrites annotation find query
to address performance issues when querying annotation table and
there is a large amount of rows.

Fixes #21902

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Kyle Brandt <kyle@kbrandt.com>
(cherry picked from commit 5ae9519)
alexanderzobnin pushed a commit that referenced this issue Feb 6, 2020
…rove database query performance (#21915)

Drop indices and create new ones and rewrites annotation find query
to address performance issues when querying annotation table and
there is a large amount of rows.

Fixes #21902

Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
Co-authored-by: Kyle Brandt <kyle@kbrandt.com>
(cherry picked from commit 5ae9519)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/annotations area/backend/db/mysql area/backend/db area/backend prio/critical Highest priority. Must be actively worked on as someone's top priority right now.
Projects
None yet
3 participants