【问题标题】:Need an explanation about a slow query with MariaDB需要一个关于 MariaDB 慢查询的解释
【发布时间】:2022-10-01 00:22:47
【问题描述】:

我有一个“简单”查询,使用 MariaDB 执行需要 0.7678 秒或更长时间。

这是查询:

select  `referenceNumber`
    from  `invoice`
    where  `groupId` = 3550
      and  `referenceNumber` >= 301
    order by  `referenceNumber` desc
    limit  1;

这些列有一个索引:\"referenceNumber\", \"groupId\"

这是EXPLAIN 的结果:

我通过创建这样的子查询找到了解决方案:

select  `referenceNumber`
    from  (
        SELECT  id
            from  `invoice`
            where  `groupId` = 3550
              and  `referenceNumber` >= 301
          ) as subquery
    JOIN  invoice as invoice  ON invoice.id = subquery.id
    order by  `referenceNumber` desc
    limit  1;

此查询大约需要 0.0011 秒。

这是 EXPLAIN 的结果:

您对第一个查询的性能不佳有解释吗?

两个令人惊讶的发现:

没有where `groupId` = 3550 的查询只需要 0.0005 秒,如下所示:

select  `referenceNumber`
    from  `invoice`
    where  `referenceNumber` >= 301
    order by  `referenceNumber` desc
    limit  1;

没有order by `referenceNumber` desc 的查询只需要 0.0011 秒,如下所示:

select  `referenceNumber`
    from  `invoice`
    where  `groupId` = 3550
      and  `referenceNumber` >= 301
    limit  1;

这是该表的架构:

CREATE TABLE `invoice` (
  `id` int(10) UNSIGNED NOT NULL,
  `groupId` int(11) NOT NULL,
  `referenceNumber` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
            COLLATE=utf8mb4_unicode_ci;

ALTER TABLE `invoice`
  ADD PRIMARY KEY (`id`),
  ADD KEY `invoice_groupid_index` (`groupId`),
  ADD KEY `invoice_referencenumber_index` (`referenceNumber`);

ALTER TABLE `invoice`
  MODIFY `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT;
COMMIT;

非常感谢您的帮助!

  • 如果您将结果粘贴为纯文本而不是肮脏的小屏幕截图,尤其是截断的屏幕截图。
  • 你有没有调整过你的服务器?有些人运行的库存配置绝对缺乏内存。
  • 您还需要在groupId, referenceNumber 上为您正在执行的查询类型建立一个索引。 groupId 索引只能让你到目前为止,其余的行必须与扫描匹配。
  • 如果首先要了解有关服务器性能的一件事,那就是 innodb_buffer_pool_size绝对地批判的。如果它设置得太小,您将无缘无故地牺牲大量性能。
  • @tadman 你完全正确!!我用groupId, referenceNumber 创建了一个索引,现在第一个查询只需要 0.0005 秒。太棒了,真的非常感谢!!

标签: mysql performance mariadb


【解决方案1】:

当涉及到索引时,如果查询涉及到 A 列和 B 列,那么在 A 列和 B 列上建立索引将无济于事。

在A上添加索引会为具有各种A值的记录创建一个查找表,并且可以为ORDERBETWEEN等涉及有序值的操作提供支持。重要的是它才不是说明与 B 相关的任何事物的顺序。

同样,B 上的索引也做同样的事情,忽略 A 的顺序。

一般来说,如果要查询WHERE A=? ORDER BY B,则需要在A,B 上建立索引。这将创建一个索引,其中数据在 A 上排序,然后在 B 上进行子排序(对于 A 的相等值)。这使得比较非常快速,它们通常可以完全在索引中发生。

【讨论】:

  • 非常感谢您的详细解释。我按照您的建议在A,B 上添加了索引。现在请求真的很快。你在 2 分钟内解决了我的问题 :)
【解决方案2】:
  • 子查询是多余的。他们可能涉及建立一个临时表,这会增加成本。 (在其他情况下这实际上是最佳的,但不是在这里。)

  • 没有ORDER BYLIMIT 会给你一个随机物品;不要那样做。在我看来,这是无效的,所以它有多快并不重要。

  • 为了提高性能,其余的需要您将KEY(groupId) 替换为

      INDEX(groupId, referenceNumber)  -- in this order
    
  • 您的某些公式使优化器陷入了使用KEY(groupId) 还是KEY(referenceNumber) 的困境。每个都有其优点和缺点。但是优化器没有足够的信息在它们之间进行选择。上面的复合索引将定位在所需的单行上。

  • 注意:我建议的索引是“复合”和“覆盖”。请参阅这些条款以供进一步参考。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-21
    • 1970-01-01
    相关资源
    最近更新 更多