可以优化查询以便不需要运行分析吗?
Posted
技术标签:
【中文标题】可以优化查询以便不需要运行分析吗?【英文标题】:Can a query be optimized so that running analyze isn't necessary? 【发布时间】:2019-09-10 20:29:45 【问题描述】:我有一个带有 mysql 数据库(所有 innodb 表)的 Drupal 站点,每隔一段时间就会“崩溃”(阅读:运行缓慢)。服务器托管是基于云的,当数据库移动到新的容器时会发生“崩溃”。连接大约 10 个表并返回单行的查询在移动后开始运行极其缓慢(1 分钟),一切都停止了。通常查询执行速度非常快(不到 0.1 秒),这不是问题。
已确定移动会导致“崩溃”,因为 MySQL 服务器丢失了其“分析”信息 - 该信息存储在内存中,并且在移动数据库时丢失。
目前无法在移动后自动运行分析。托管公司建议重新编写查询,以便不需要进行分析。我想问问社区这是否有意义,以及我可能会如何重写它。
这是从 OP 的 pastebin 复制的信息:
Query_time:0.052842 Lock_time:0.000530 Rows_sent:1 Rows_examined:61031
SELECT node__field_last_sl_play.field_last_sl_play_value AS node__field_last_sl_play_field_last_sl_play_value, node_field_data.nid AS nid, node_field_data_node__field_album.nid AS node_field_data_node__field_album_nid, node_field_data_node__field_artist.nid AS node_field_data_node__field_artist_nid, node_field_data_node__field_event.nid AS node_field_data_node__field_event_nid, votingapi_result_node_field_data.id AS votingapi_result_node_field_data_id, node_field_data_node__field_lifestyle.nid AS node_field_data_node__field_lifestyle_nid
FROM
node_field_data node_field_data
LEFT JOIN node__field_album node__field_album ON node_field_data.nid = node__field_album.entity_id AND node__field_album.deleted = '0' AND (node__field_album.langcode = node_field_data.langcode OR node__field_album.bundle = 'track')
LEFT JOIN node_field_data node_field_data_node__field_album ON node__field_album.field_album_target_id = node_field_data_node__field_album.nid
LEFT JOIN node__field_artist node_field_data_node__field_album__node__field_artist ON node_field_data_node__field_album.nid = node_field_data_node__field_album__node__field_artist.entity_id AND node_field_data_node__field_album__node__field_artist.deleted = '0' AND (node_field_data_node__field_album__node__field_artist.langcode = node_field_data_node__field_album.langcode OR node_field_data_node__field_album__node__field_artist.bundle = 'album')
LEFT JOIN node_field_data node_field_data_node__field_artist ON node_field_data_node__field_album__node__field_artist.field_artist_target_id = node_field_data_node__field_artist.nid
LEFT JOIN node__field_event node__field_event ON node_field_data.nid = node__field_event.entity_id AND node__field_event.deleted = '0' AND (node__field_event.langcode = node_field_data.langcode OR node__field_event.bundle = 'track')
LEFT JOIN node_field_data node_field_data_node__field_event ON node__field_event.field_event_target_id = node_field_data_node__field_event.nid
LEFT JOIN votingapi_result votingapi_result_node_field_data ON node_field_data.nid = votingapi_result_node_field_data.entity_id AND (votingapi_result_node_field_data.entity_type = 'node' AND votingapi_result_node_field_data.function = 'vote_sum' AND votingapi_result_node_field_data.type = 'vote')
LEFT JOIN node__field_lifestyle node__field_lifestyle ON node_field_data.nid = node__field_lifestyle.entity_id AND node__field_lifestyle.deleted = '0'
LEFT JOIN node_field_data node_field_data_node__field_lifestyle ON node__field_lifestyle.field_lifestyle_target_id = node_field_data_node__field_lifestyle.nid
LEFT JOIN node__field_last_sl_play node__field_last_sl_play ON node_field_data.nid = node__field_last_sl_play.entity_id AND node__field_last_sl_play.deleted = '0'
WHERE (node_field_data.status = '1') AND (node_field_data.type IN ('track'))
ORDER BY node__field_last_sl_play_field_last_sl_play_value DESC
LIMIT 1 OFFSET 0;
此查询的解释报告:
EXPLAIN
1 SIMPLE node_field_data index_merge node_field__type__target_id,node__status_type node_field__type__target_id,node__status_type 34,35
NULL
2288 Using intersect(node_field__type__target_id,node__status_type); Using where; Using index; Using temporary; Using filesort
1 SIMPLE node__field_album ref PRIMARY,bundle PRIMARY 5 dbname.node_field_data.nid,const 1 Using where
1 SIMPLE node_field_data_node__field_album ref PRIMARY,node__id__default_langcode__langcode PRIMARY 4 dbname.node__field_album.field_album_target_id 1 Using where; Using index
1 SIMPLE node_field_data_node__field_album__node__field_artist ref PRIMARY,bundle PRIMARY 5 dbname.node_field_data_node__field_album.nid,const 1 Using where
1 SIMPLE node_field_data_node__field_artist ref PRIMARY,node__id__default_langcode__langcode PRIMARY 4 dbname.node_field_data_node__field_album__node__field_artist.field_artist_target_id 1 Using where; Using index
1 SIMPLE node__field_event ref PRIMARY,bundle PRIMARY 5 dbname.node_field_data.nid,const 1 Using where
1 SIMPLE node_field_data_node__field_event ref PRIMARY,node__id__default_langcode__langcode PRIMARY 4 dbname.node__field_event.field_event_target_id 1 Using where; Using index
1 SIMPLE votingapi_result_node_field_data ref vote_result_field__type__target_id,vote_result_field__entity_id__target_id vote_result_field__entity_id__target_id 5 dbname.node_field_data.nid 1 Using where
1 SIMPLE node__field_lifestyle ref PRIMARY PRIMARY 5 dbname.node_field_data.nid,const 1
1 SIMPLE node_field_data_node__field_lifestyle ref PRIMARY,node__id__default_langcode__langcode PRIMARY 4 dbname.node__field_lifestyle.field_lifestyle_target_id 1 Using where; Using index
1 SIMPLE node__field_last_sl_play ref PRIMARY PRIMARY 5 dbname.node_field_data.nid,const 1
表定义:
CREATE TABLE `node_field_data` (
`nid` int(10) unsigned NOT NULL,
`vid` int(10) unsigned NOT NULL,
`type` varchar(32) CHARACTER SET ascii NOT NULL COMMENT 'The ID of the target entity.',
`langcode` varchar(12) CHARACTER SET ascii NOT NULL,
`title` varchar(255) NOT NULL,
`uid` int(10) unsigned NOT NULL COMMENT 'The ID of the target entity.',
`status` tinyint(4) NOT NULL,
`created` int(11) NOT NULL,
`changed` int(11) NOT NULL,
`promote` tinyint(4) NOT NULL,
`sticky` tinyint(4) NOT NULL,
`revision_translation_affected` tinyint(4) DEFAULT NULL,
`default_langcode` tinyint(4) NOT NULL,
`rh_action` varchar(255) DEFAULT NULL,
`rh_redirect` varchar(255) DEFAULT NULL,
`rh_redirect_response` int(11) DEFAULT NULL,
PRIMARY KEY (`nid`,`langcode`),
KEY `node__id__default_langcode__langcode` (`nid`,`default_langcode`,`langcode`),
KEY `node__vid` (`vid`),
KEY `node_field__type__target_id` (`type`),
KEY `node_field__created` (`created`),
KEY `node_field__changed` (`changed`),
KEY `node__frontpage` (`promote`,`status`,`sticky`,`created`),
KEY `node__status_type` (`status`,`type`,`nid`),
KEY `node__title_type` (`title`(191),`type`(4)),
KEY `node_field__uid__target_id` (`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='The data table for node entities.'
【问题讨论】:
顺便说一句,在解析并创建执行计划之前,无法执行查询。 @symcbean 您是说必须在执行查询之前运行分析?如果是这样,为什么这不会自动发生?奇怪的是这已经好 2 年了,现在突然出现问题了。 FWIW 这是一家著名的托管公司,使用 Google 进行容器化。 它会交换吗?如果是这样,你把事情调得太高了。让我们看看 my.cnf 和 VM 的大小。 @RickJames 来自 phpmyadmin 的“变量”是否有效? pastebin.com/jqLBnHU0 表的 innodb stats 应该在重启后第一次打开表时刷新,与 ANALYZE TABLE 完全相同。见dev.mysql.com/doc/refman/5.7/en/… 【参考方案1】:codesmith,您的查询没有任何问题。当您的表具有合理的索引而不是 1 分钟时,它会在 0.1 秒内运行。既然您和您的托管公司知道移动到另一个容器需要 ANALYZE 来完成该过程,为什么这不是他们过程的一部分? “FWIW 这是一家著名的托管公司,使用 Google 进行容器化。”尝试说服托管公司加倍努力并分析每个表 - 就在他们“移动”之后,以避免在接下来的几天(或几周)出现“异常长时间运行的查询”时出现这种发现。如果时间允许,我仍然想与你进行 Skype TALK。
【讨论】:
以上是关于可以优化查询以便不需要运行分析吗?的主要内容,如果未能解决你的问题,请参考以下文章