如何最好地优化此 MariaDB 查询

问题描述 投票:0回答:1

尝试优化一个查询,该查询最终总是使用“Using where;Usingtemporary;Usingfilesort”并花费近 2 秒的时间完成。查询中的所有匹配项都已索引或主键。

它只是抓取网站文章中的最后几条评论,并列出它们,但它需要抓取文章标题和用户用户名等内容。

查询:

SELECT
    c.`comment_id`,
    c.`article_id`,
    c.`time_posted`,
    a.`title`,
    a.`slug`,
    u.username,
    a.`date`
FROM
    `articles_comments` c
INNER JOIN `articles` a ON
    c.`article_id` = a.`article_id`
INNER JOIN `users` u ON
    u.user_id = c.author_id
WHERE
    a.`active` = 1 AND c.`approved` = 1
ORDER BY
    c.`comment_id`
DESC
LIMIT 5;

桌子:

CREATE TABLE `articles_comments` (
  `comment_id` int(11) UNSIGNED NOT NULL,
  `article_id` int(11) NOT NULL,
  `author_id` int(11) NOT NULL,
  `guest_username` varchar(255) DEFAULT NULL,
  `time_posted` int(11) NOT NULL,
  `comment_text` text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  `spam` tinyint(1) NOT NULL DEFAULT 0,
  `spam_report_by` int(11) DEFAULT NULL,
  `last_edited` int(11) NOT NULL DEFAULT 0,
  `last_edited_time` int(11) DEFAULT NULL,
  `edit_counter` int(11) NOT NULL DEFAULT 0,
  `approved` tinyint(1) NOT NULL DEFAULT 1,
  `total_likes` int(10) UNSIGNED NOT NULL DEFAULT 0,
  `lock_timer` datetime DEFAULT NULL,
  `locked_by_id` int(10) UNSIGNED DEFAULT NULL,
  `promoted` tinyint(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin;


ALTER TABLE `articles_comments`
  ADD PRIMARY KEY (`comment_id`),
  ADD KEY `author_id` (`author_id`),
  ADD KEY `article_id` (`article_id`),
  ADD KEY `approved` (`approved`),
  ADD KEY `last_edited` (`last_edited`),
  ADD KEY `time_posted` (`time_posted`);


ALTER TABLE `articles_comments`
  MODIFY `comment_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;


CREATE TABLE `articles` (
  `article_id` int(11) UNSIGNED NOT NULL,
  `author_id` int(11) UNSIGNED NOT NULL,
  `guest_username` varchar(255) DEFAULT NULL,
  `guest_email` varchar(255) DEFAULT NULL,
  `guest_ip` varchar(100) DEFAULT NULL,
  `date` int(11) NOT NULL,
  `edit_date` datetime DEFAULT NULL,
  `date_submitted` int(11) DEFAULT NULL,
  `title` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `slug` varchar(120) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL,
  `tagline` text DEFAULT NULL,
  `text` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
  `comment_count` int(11) UNSIGNED NOT NULL DEFAULT 0,
  `active` int(1) NOT NULL DEFAULT 1,
  `show_in_menu` tinyint(1) NOT NULL DEFAULT 0,
  `views` int(11) UNSIGNED NOT NULL DEFAULT 0,
  `submitted_article` tinyint(1) NOT NULL DEFAULT 0,
  `admin_review` tinyint(1) NOT NULL DEFAULT 0,
  `reviewed_by_id` int(11) UNSIGNED DEFAULT NULL,
  `submitted_unapproved` tinyint(1) NOT NULL DEFAULT 0,
  `comments_open` tinyint(1) NOT NULL DEFAULT 1,
  `draft` tinyint(1) NOT NULL DEFAULT 0,
  `tagline_image` text DEFAULT NULL,
  `thumbnail_alt_text` varchar(100) DEFAULT NULL,
  `gallery_tagline` int(10) UNSIGNED NOT NULL DEFAULT 0,
  `locked` tinyint(1) NOT NULL DEFAULT 0,
  `locked_by` int(11) UNSIGNED DEFAULT NULL,
  `locked_date` int(11) DEFAULT NULL,
  `preview_code` varchar(10) DEFAULT NULL,
  `total_likes` int(10) UNSIGNED NOT NULL DEFAULT 0,
  `moderated_comments` tinyint(1) NOT NULL DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci;


ALTER TABLE `articles`
  ADD PRIMARY KEY (`article_id`),
  ADD KEY `date` (`date`),
  ADD KEY `author_id` (`author_id`),
  ADD KEY `slug` (`slug`);
ALTER TABLE `articles` ADD FULLTEXT KEY `title` (`title`,`text`);
ALTER TABLE `articles` ADD FULLTEXT KEY `title_2` (`title`);
ALTER TABLE `articles` ADD FULLTEXT KEY `text` (`text`);


ALTER TABLE `articles`
  MODIFY `article_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;



CREATE TABLE `users` (
  `user_id` int(11) UNSIGNED NOT NULL,
  `register_date` int(11) DEFAULT NULL,
  `email` varchar(233) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `supporter_email` varchar(233) DEFAULT NULL,
  `supporter_type` text DEFAULT NULL,
  `supporter_end_date` datetime DEFAULT NULL,
  `supporter_plus_end` datetime DEFAULT NULL,
  `supporter_last_paid_date` datetime DEFAULT NULL,
  `show_supporter_status` tinyint(1) NOT NULL DEFAULT 1,
  `password` varchar(255) DEFAULT NULL,
  `username` varchar(32) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
  `user_group` int(1) NOT NULL DEFAULT 3,
  `secondary_user_group` int(11) NOT NULL DEFAULT 0,
  `ip` varchar(255) DEFAULT NULL,
  `comment_count` int(11) UNSIGNED NOT NULL DEFAULT 0,
  `avatar` text DEFAULT NULL,
  `author_picture` text DEFAULT NULL,
  `avatar_uploaded` tinyint(1) NOT NULL DEFAULT 0,
  `avatar_gallery` text DEFAULT NULL,
  `forum_posts` int(11) UNSIGNED NOT NULL DEFAULT 0,
  `steam` varchar(255) DEFAULT NULL,
  `article_bio` text DEFAULT NULL,
  `about_me` text DEFAULT NULL,
  `twitter_on_profile` varchar(120) DEFAULT NULL,
  `banned` tinyint(1) NOT NULL DEFAULT 0,
  `ban_reason` text DEFAULT NULL,
  `oauth_uid` varchar(200) DEFAULT NULL,
  `oauth_provider` varchar(200) DEFAULT NULL,
  `twitter_username` varchar(200) DEFAULT NULL,
  `last_login` int(11) DEFAULT NULL,
  `website` text DEFAULT NULL,
  `auto_subscribe` tinyint(1) NOT NULL DEFAULT 0,
  `auto_subscribe_email` tinyint(1) NOT NULL DEFAULT 0,
  `email_on_pm` tinyint(1) NOT NULL DEFAULT 1,
  `theme` varchar(32) DEFAULT NULL,
  `supporter_link` text NOT NULL,
  `hide_developer_status` tinyint(1) NOT NULL DEFAULT 0,
  `youtube` text NOT NULL,
  `steam_id` bigint(20) DEFAULT NULL,
  `steam_username` text NOT NULL,
  `distro` text NOT NULL,
  `public_email` tinyint(1) NOT NULL DEFAULT 0,
  `auto_subscribe_new_article` tinyint(1) NOT NULL DEFAULT 0,
  `facebook` text DEFAULT NULL,
  `email_options` int(11) NOT NULL DEFAULT 2,
  `activated` tinyint(1) NOT NULL DEFAULT 0,
  `activation_code` varchar(255) DEFAULT NULL,
  `twitch` text DEFAULT NULL,
  `mastodon` text DEFAULT NULL,
  `gogprofile` text DEFAULT NULL,
  `in_mod_queue` tinyint(1) NOT NULL DEFAULT 1,
  `mod_approved` int(11) NOT NULL DEFAULT 0,
  `login_emails` tinyint(1) NOT NULL DEFAULT 1,
  `pc_info_public` tinyint(1) NOT NULL DEFAULT 0,
  `pc_info_filled` tinyint(1) NOT NULL DEFAULT 0,
  `per-page` int(11) NOT NULL DEFAULT 30,
  `articles-per-page` int(11) NOT NULL DEFAULT 15,
  `forum_type` varchar(15) NOT NULL DEFAULT 'normal_forum',
  `single_article_page` tinyint(1) NOT NULL DEFAULT 0,
  `submission_emails` tinyint(1) NOT NULL DEFAULT 0,
  `game_developer` tinyint(1) NOT NULL DEFAULT 0,
  `display_comment_alerts` tinyint(1) NOT NULL DEFAULT 1,
  `display_quote_alerts` tinyint(1) NOT NULL DEFAULT 1,
  `display_like_alerts` tinyint(1) NOT NULL DEFAULT 1,
  `admin_comment_alerts` tinyint(1) NOT NULL DEFAULT 1,
  `timezone` text DEFAULT NULL,
  `google_email` text NOT NULL,
  `email_articles` varchar(32) DEFAULT NULL,
  `mailing_list_key` text DEFAULT NULL,
  `global_search_visible` tinyint(1) NOT NULL DEFAULT 0,
  `get_pms` tinyint(1) NOT NULL DEFAULT 1,
  `private_profile` tinyint(1) NOT NULL DEFAULT 1,
  `social_stay_cookie` tinyint(1) NOT NULL DEFAULT 0,
  `lifetime_supporter` tinyint(1) DEFAULT 0,
  `profile_address` varchar(60) DEFAULT NULL,
  `hide_adverts` tinyint(1) NOT NULL DEFAULT 0,
  `full_rss_key` varchar(100) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin;




ALTER TABLE `users`
  ADD PRIMARY KEY (`user_id`);

ALTER TABLE `users`
  MODIFY `user_id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

使用解释给了我这个:

1   SIMPLE  a   ALL PRIMARY NULL    NULL    NULL    17487   Using where; Using temporary; Using filesort    
1   SIMPLE  c   ref author_id,article_id,approved   article_id  4   gamingonlinux.a.article_id  5   Using index condition; Using where  
1   SIMPLE  u   eq_ref  PRIMARY PRIMARY 4   gamingonlinux.c.author_id   1   Using where 

这是在 MariaDB 10.6 上

mariadb query-optimization
1个回答
0
投票

当我在 Dbfiddle 上测试您的查询时,我看到 EXPLAIN 显示了不同的输出:

id 选择类型 桌子 类型 可能的键 key_len 参考 额外
1 简单 c 参考 author_id,article_id,已批准 已批准 1 常量 1 使用地点
1 简单 a eq_ref 小学 小学 4 fiddle.c.article_id 1 使用地点
1 简单 eq_ref 小学 小学 4 fiddle.c.author_id 1 使用地点

您可以看到这消除了文件排序和临时表。这两者都可能会降低性能。

此版本的 EXPLAIN 还将连接转换为

type: eq_ref
连接,这意味着它们正在通过各自的主键对表
a
u
进行查找。第一个表
c
使用辅助键查找,由
type: ref
表示。

我在测试表中使用零行进行测试,这通常会导致不同的优化策略,因为成本估算不同。但它表明可以利用当前的索引获得更好的优化。

始终值得尝试运行

ANALYZE TABLE
以确保优化器具有索引的当前统计信息,因此其估计更加准确。此命令可以随时在 InnoDB 表上快速且安全地运行。

如果这没有帮助,那么您可能必须使用查询提示来强制表连接的特定顺序。请参阅https://mariadb.com/kb/en/index-hints-how-to-force-query-plans/

© www.soinside.com 2019 - 2024. All rights reserved.