PmaControl logo PmaControl
  • 首页
  • PmaControl
    • AI智能代理 13个本地代理
    • 定价方案 Community、Cloud、On-Premise、Premium
    • 文档 指南、API、架构
    • 版本历史 全部 5.x 稳定版本
    • 插件市场 社区插件
    • 客户 28+企业
    • 常见问题 25个问题 / 7个类别
    数据库
    • MariaDB 35 篇文章
    • MySQL 15 篇文章
    • Galera Cluster 6 篇文章
    • MaxScale 4 篇文章
    • ProxySQL 3 篇文章
    • Amazon Aurora MySQL 0 篇文章
    • Azure Database 0 篇文章
    • ClickHouse 0 篇文章
    • GCP CloudSQL 0 篇文章
    • Percona Server 0 篇文章
    • SingleStore 0 篇文章
    • TiDB 0 篇文章
    • Vitess 0 篇文章
    解决方案
    • 全天候支持 MariaDB & MySQL紧急支持
    • Observabilité SQL 监控、告警、拓扑
    • Haute disponibilité 复制、故障转移、Galera
    • Disaster Recovery 备份、恢复、RPO/RTO
    • Sécurité & conformité 审计、GDPR、SOC2
    • Migration & upgrade 零停机、pt-osc、gh-ost
  • 定价方案
  • 资源
    • 文档 技术指南与API
    • MySQL 优化中心 Markdown 索引、指标、参数、故障
    • 常见问题 25个常见问题
    • 客户评价 客户反馈与案例
    • 博客 文章与洞察
    • 路线图 即将推出的功能
    专业领域
    • Observabilité SQL 监控、告警、Dot3拓扑
    • Haute disponibilité 复制、故障转移、Galera
    • Sécurité & conformité 审计、GDPR、SOC2、ISO 27001
    • Disaster Recovery 备份、恢复、RPO/RTO
    • Performance & optimisation Digests、EXPLAIN、调优
    • Migration & upgrade 零停机、pt-osc
    快速链接
    • GitHub Wiki 26页 — 安装、引擎、插件
    • 源代码 GitHub官方仓库
    • 全天候支持 MariaDB & MySQL紧急支持
    • 预约演示 30分钟 — 真实架构
  • 全天候支持
  • 预约演示
预约演示
🇫🇷 FR Français 🇬🇧 EN English 🇵🇱 PL Polski 🇷🇺 RU Русский 🇨🇳 ZH 中文 🇸🇦 AR العربية
← 返回博客

缓存和索引都已就绪,页面为何仍然缓慢:PmaControl 中的 MariaDB 性能分析

发布于 2026年10月9日 作者 Aurélien LEQUOY
pmacontrol mariadb performance sql benchmark architecture
分享 X LinkedIn Facebook Email PDF
缓存和索引都已就绪,页面为何仍然缓慢:PmaControl 中的 MariaDB 性能分析

“图形已经在缓存中。为什么架构页面仍然需要几秒钟才能显示?”

这个问题导致我们在 PmaControl 中进行了一个非常简短的修复。 没有缺失的索引。也不需要重新计算绘图。 MariaDB 选择了一种昂贵的方式来查找要显示的图形的生成。

以下是此比较的指标、SQL 和限制。我们区分提出问题的客户端和已经快速执行初始查询的测试实例。

更新于 2026 年 10 月 10 日。 下文加入了下午 1:29 记录的 SQL 测量结果。由于 10 月 9 日截图时使用的连接不稳定,我们又在下午 1:45 左右从局域网内的一台服务器重新测量了下载时间。每组测试均保留各自的环境、图表数量和测量范围:SQL、HTTP 下载或 Chromium 页面加载。

用装图纸的盒子来解释

想象一下一个装满盒子的图书馆。每个盒子包含一代拓扑的绘图。绘图已经完成:这是我们的 SVG 缓存。

要显示页面,应用程序仍需找到正确的盒子、取出其中的图纸,再把它们排列到屏幕上。图书馆的目录已经存在,这就是 SQL 索引。

但仅有目录还不够。在速度缓慢的情况下,MariaDB 选择迭代数百万个条目来准备中间匹配列表。对于我们感兴趣的验证,找到单个匹配就足够了。

修复明确表达了这一检查。返回的图纸完全相同,而查找过程避开了代价高昂的绕行。

已经缓存的内容

SVG 保存在 dot3_graph 中。 dot3_cluster 表将它们与拓扑生成相关联。该页面已经使用 单个 SQL 查询 检索了所有图表,该查询特别返回:

SELECT dg.id, dg.svg, dg.height, dg.width,
       (dg.height * dg.width) AS area,
       dc.date_inserted AS date_refresh
FROM dot3_cluster dc
JOIN dot3_graph dg ON dg.id = dc.id_dot3_graph
-- 该条件选择已准备好显示的代次。

因此,浏览器会收到图形及其高度、宽度和面积。App/Webroot/js/Architecture/topology.js 中的代码已经负责在浏览器中排布图形。本次修复没有修改这一算法。

缓存避免在每次访问时进行绘图。它不会避免搜索、传输和显示绘图。此 SVG 缓存与 MariaDB 查询缓存和浏览器的 HTTP 缓存是分开的。

不,没有缺失索引

正如 SHOW INDEX FROM dot3_cluster 所确认的,慢速实例已经具有此唯一索引:

-- 现有索引,以定义形式显示:
UNIQUE KEY id_dot3_information_2
    (id_dot3_information, id_dot3_graph)

搜索过滤 id_dot3_information,即索引的第一列。因此,这使得找到一代的簇成为可能。

问题出在执行计划,即 MariaDB 执行 SQL 时选择的策略。初始版本使用 EXISTS 检查某一代是否至少包含一个集群。在这个实例上,该选择触发了物化:MariaDB 扫描约 433 万个历史索引项来准备中间结果。

这并不意味着浏览器收到了四百万张图表;它实际收到的是 61 张图表。过量工作发生在数据库中,早于有用结果的返回。433 万描述的是首次诊断时发现的扫描量级,并非传给 PHP 的行数。10 月 10 日的测量显示,该实例的表目前约有 520 万行;因此,初始文章与新一轮测试的数据量并不完全相同。

在非常宽的扫描期间可以使用索引。因此,索引的存在本身并不能保证短访问。

MariaDB、InnoDB / RocksDB 配置和表

两个环境都使用 MariaDB 11.8.9,但软件包不同:根据 10 月 10 日的记录,客户环境使用 11.8.9-deb13;测试实例使用 11.8.9-MariaDB-deb12-log,并已在服务器上直接核实。客户使用 PHP 8.4 重放 SQL;测试实例使用 FrankenPHP / PHP 8.5.9。

下图涵盖了页面上 16 个查询使用的 16 个应用程序表,超出了 SVG 查询中的三个表。有用的列、键和引擎来自测试实例的实际图表,记录于10 月 10 日下午 3:06。表存在检查还查询 information_schema.tables,这是一个元数据视图,不是分类为 InnoDB 或 RocksDB 的应用程序表。

表格图,第 1 部分(共 2 部分):生成和 SVG、会话和导航; dot3_information在RocksDB中,其他七个表在InnoDB中。

表格图,第 2 部分(共 2 部分):转换、过滤器、警报和配置;八个 InnoDB 表。

打开矢量图大。实线表示已声明的外键;虚线表示 SQL 使用的逻辑连接。没有显示链接的表将单独查询。该图显示了关系,而不是查询执行的顺序。

测试实例中 SVG 查询涉及的表 观察到的存储引擎
dot3_information RocksDB
dot3_cluster InnoDB
dot3_graph InnoDB

页面上的另外 13 个表均使用 InnoDB。上方的完整图表和可下载的存储引擎与大小清单列出了详细信息。

因此,SVG 查询在测试实例上跨越两个存储引擎。dot3_information 的可用性索引属于 RocksDB;dot3_cluster 的唯一索引以及 dot3_graph 中的 SVG 数据属于 InnoDB。修复保留了这些引擎和索引。本轮测试比较的是两种 SQL 写法,并未测量将表从 InnoDB 转换为 RocksDB 的效果。客户的测量记录没有提供其存储引擎,因此我们不会把测试实例上观察到的结构归于客户环境。

测试实例的匿名 .cnf 配置按加载顺序汇总了各包含文件中的服务器配置段,并删除了网络标识和机密。由于后面的文件可能覆盖前面的设置,实际读取到的全局变量给出了最终生效值,其中包括 2 GiB InnoDB 缓冲池、2 GiB RocksDB 块缓存、最多 128 个连接、tmp_table_size 和 max_heap_table_size 各 64 MiB,以及已禁用的查询缓存。

这些参数采集于下午 3:14,晚于下午 1:45 的测量;部分变量可能动态变化。.cnf 资源描述的是观察到的配置及其覆盖关系,并删去了敏感值,不能直接作为配置文件应用。测量记录中没有客户的 .cnf 配置。

SQL 修改前后

改动位于 App/Library/Dot3LatestGeneration.php,用于选择最新且已准备好的代次。

前 :

AND EXISTS (
    SELECT 1
    FROM dot3_cluster dc_ready
    WHERE dc_ready.id_dot3_information = di.is_svg_generated
)

后 :

AND (
    SELECT dc_ready.id_dot3_information
    FROM dot3_cluster dc_ready
    WHERE dc_ready.id_dot3_information = di.is_svg_generated
    LIMIT 1
) IS NOT NULL

为什么这里是等价的?外部请求已施加 di.is_svg_generated > 0。如果存在匹配的簇,则子查询返回该正标识符。否则,没有结果的标量子查询将返回 NULL。因此,该条件始终检查这一代的簇是否存在。

标量子查询避免了使用 EXISTS 观察到的物化计划。引擎可以搜索索引中的代并在第一个匹配处停止。如果没有可用的现成一代,则使用的后备解决方案保持不变。

这并不是说 EXISTS 很慢的规则。 在我们的另一个实例上,旧查询已经使用了高效的 FirstMatch 策略。重写所有 EXISTS 将是一个糟糕的结论:您必须检查和测量每个查询的计划。

一位客户:10 月 10 日的新 SQL 测量

在一位客户处于下午 1:29 左右进行的测量,使用生产数据对每种写法各执行十次;排除一次预热,并交替执行修复前后的查询。生产代码已经包含修复;这里的“之前”是为比较而执行旧的 EXISTS 查询,“之后”则是带 LIMIT 1 的标量子查询。

SQL 测量 之前 (EXISTS) 之后 (LIMIT 1)
SVG 查询,最小值–最大值 4 434,17–5 297,38 ms 2,69–6,20 ms
SVG 查询,中位数 5 044,59 ms 3,32 ms
16 个查询合计,中位数 5 068,52 ms 12,92 ms
返回的图表 61 61
SVG 体积 995 307 字节 995 307 字节
本次测量的索引读取计数器 5 199 176 3

在本次测量中,主要查询从 5.04 秒降至 3.32 毫秒,约快 1,520 倍。修复前后的 61 个图形完全相同。当前体积与首次诊断记录的 995,437 字节相差 130 字节;两者采集日期不同,而新一轮测试的两种写法返回了相同内容。

修复前的 EXPLAIN 计划对物化过程估算为 4,406,092 个条目;修复后,使用索引的相关子查询估算为 81 个条目。这些估算值不是实际读取次数。本次测量的索引读取计数器显示为修复前 5,199,176 次、修复后 3 次;当时 dot3_cluster 包含 5,198,990 行。执行计划估算、实际读取计数和传给浏览器的图形数量是三种不同指标。

其他 15 个请求的中值均保持在 10 毫秒以下。有些波动:例如,警报计数从 9.21 毫秒到 0.85 毫秒,之前偶尔会达到 15.55 毫秒。此结果并不表明修复加快了计数速度:服务器的负载约为 6,并且这些请求紧随 5 秒的请求之后。代码更改仅涉及 SVG 的选择。

此活动重播的唯一更改请求(会话刷新)已执行,然后被取消。 该报告衡量 SQL;它不测量下载或完整的浏览器加载。 时间包括 mysqli 的完整检索结果,包括大约 1 MB 的 SVG。

客户环境中的查询 之前(毫秒) 之后(毫秒)
1。阅读登录会话 0,34 0,34
2。刷新会话,然后取消 0,16 0,19
3。加载 61 图表及其尺寸 5 044,59 3,32
4。列出客户 0,53 0,29
5。列出环境 0,78 0,15
6。列表标签 0,60 0,22
7。搜索导航提要 1,59 0,64
8。构建菜单 5,26 4,24
9。统计活动警报 9,21 0,85
10。选择菜单项 0,78 0,66
11。检查翻译键 0,53 0,15
12。阅读翻译 0,48 0,18
13。查看配置表 0,20 0,17
14。读取许可证设置 0,17 0,15
15。检查隐藏横幅表 0,18 0,15
16。阅读许可证横幅的屏蔽 0,30 0,13
每次运行的总和,中位数 5 068,52 12,92

包含时间范围和两份执行计划的匿名 SQL 测量记录补充了此表。

客户下载时间:比较假设

为了完成 HTTP 比较,我们从服务器获取测试实例上测得的下载时间,如下节所示。我们假设这些持续时间对于客户来说是相同的。 这些值是两种环境共同的假设;它们不构成客户端的新 HTTP 措施。

作为假设沿用的 HTML 文档下载时间 之前 之后
测试实例上的 Chromium 中位数 42,90 ms 37,45 ms

客户环境的首字节时间和完整页面加载时间没有重新测量,也不能直接套用测试实例的总时间,因为修复前仅客户的 SVG 查询就耗时五秒。我们将实际测得的 SQL 时间与假设的传输时间分开,不虚构浏览器加载时间。

下载和浏览器:来自服务器的新测量

为消除早期截图所用连接带来的不确定性,我们在10 月 10 日下午 1:45 左右进行了另一轮测试:从一台 Debian 12 服务器访问局域网内的测试实例。测试使用同一个未筛选的架构页面、同一个临时只读账户、30 个图形、1440 × 900 像素视口和 Chromium 152。浏览器 HTTP 缓存已禁用;每种写法排除一次预热,随后保留修复前十次和修复后十次加载。

目标服务器使用 MariaDB 11.8.9 和 FrankenPHP / PHP 8.5.9。应用代码对应提交 4207dfbe5e7d1709dbbd2efdd2cff8c1e6619dc1;在“之前”版本中,仅 Dot3LatestGeneration.php 取自其父提交 366b200703ff7550ec01d33e2c7d49c0b570ab15。测量通过局域网内临时提供工作树内容的 HTTPS 服务器完成。生产环境仍运行修复后的代码。

中位数(以毫秒为单位):

Chromium 中测量的阶段 之前 (EXISTS) 之后 (LIMIT 1)
第一个字节,包括 PHP 和传输 62,35 50,90
下载 HTML 文档 42,90 37,45
收到文件 → 事件 load 416,05 392,20
满载 → load 523,15 488,40

10 月 10 日的测量结果:客户端 61 个图表的 SQL 从 5.04 秒缩短到 3.32 毫秒;测试实例上的 30 个图表的浏览器加载时间从 523.15 毫秒到 488.40 毫秒。这两个活动具有不同的边界。

文档下载的变化范围为之前 33.2 到 61.3 毫秒,之后 32.3 到 55.1 毫秒。满载变化范围为前472.3 至 681.5 毫秒,后444.5 至 669.7 毫秒。这些系列重叠:它们在此过程中显示了大约半秒的加载,而没有建立 34.75 毫秒的可重现浏览器增益。

显示的 30 个 SVG 在 20 个负载中的每一个上都具有相同的 SHA-256。两种变体的解压缩文档大小均为 2,240,909 字节。其压缩后的主体大约为671,254 字节,或者按 Chromium 计算,包含标头大约为 671,554 字节。该 HTML 卷和这 30 个图表属于测试实例;它们不对应于客户端 61 个图形的 995,307 字节 SVG。

另一次独立的 curl --compressed 检查在预热后对每种写法发送十个请求,确认传输时间仍有波动:下载中位数为修复前 70.85 毫秒、修复后 93.80 毫秒,完整 HTTP 响应为 119.97 和 145.62 毫秒。curl 不加载页面资源,也不执行 JavaScript。解压缩、HTTP 客户端、协商出的协议和服务器负载都会造成与 Chromium 的差异;这些差异不能证明 SQL 发生了回退。

每次访问都会测量里程碑,然后单独汇总:中位数之和不一定是总数的中位数。收到文档后的时间包括其他资源、HTML解析、JavaScript、渲染。我们不仅仅将其归因于图表的位置。第一个字节已经包含了 PHP 准备;预计 PHP 时间不会添加到总数中。

12,948、2,952 和 843 毫秒的旧加载时间仍是 10 月 9 日的历史观测值,可在存档 CSV 中查看。其 470 至 535 毫秒的下载时间受当时不稳定连接影响,已不再作为网络基准。新的 30 图形测试无法重建 61 图形实例的浏览器加载时间。

测试实例上的新 SQL 比较(单个只读快照中的 10 个交替对,并且为会话禁用了 MariaDB 查询缓存)的结果是之前 6.94 毫秒,之后 5.81 毫秒。完整结果和 2,172,396 字节的 SVG 相同。最初的计划仍然使用 FirstMatch:即使 dot3_cluster 中有 6,591,509 行,该实例也不会重现其他服务器昂贵的实现。因此,仅表的大小不足以预测速度缓慢。

测试实例:10 月 9 日的 16 个查询明细

下方明细表保留了 10 月 9 日的检测结果:使用未筛选页面、只读账户和 30 个图形。排除首次预热加载后,每个版本保留五次加载。该表并非 10 月 10 日对 16 个查询的新测量。

应用程序分析器在十次加载的每一次都记录到16 个查询。下表每一行对应一个在修复前后各执行一次的查询,最后一行给出总计。所列时间是 PHP 驱动端测得的 SQL 调用中位数,单位为毫秒,并不只代表 MariaDB 引擎内部耗时。

查询 之前(毫秒) 之后(毫秒)
1。阅读登录会话 0,31 0,34
2。刷新会话 0,29 0,27
3。加载 30 图表及其尺寸 5,86 5,57
4。列出客户 0,37 0,34
5。列出环境 0,23 0,27
6。列表标签 0,23 0,29
7。搜索导航提要 0,71 1,07
8。构建菜单 3,02 3,04
9。统计活动警报 1,11 1,09
10。选择菜单项 0,67 0,67
11。检查翻译键 0,33 0,31
12。阅读翻译 0,30 0,29
13。查看配置表 0,33 0,31
14。读取许可证设置 0,22 0,23
15。检查隐藏横幅表 0,32 0,31
16。阅读许可证横幅的屏蔽 0,18 0,22
总计,中位数 14,53 14,59

总计是为每个负载计算的总和的中位数。将每行的中位数相加不一定会给出该值。

在此测试实例中,没有表现出显着的整体 SQL 增益。 0.06 毫秒的差异是最小的。这说明:MariaDB 已经为旧查询选择了一个好的计划。该修复针对的是生产实例上遇到的成本高昂的计划。

此计数涵盖了分析器记录的三个连接上初始 PHP 呈现的应用程序请求。它不包括后续 AJAX 调用和内部登录命令。这 16 个请求不应分配给所有用户配置文件或所有安装。

另请检查结果是否正确

只有显示正确图形时,更快的页面才有意义。验证覆盖修复前后结果是否一致、代次已准备或缺失时的行为,以及后备路径。

使用 MariaDB CTE 中定义的测试数据执行了九个场景,而没有插入到应用程序表中。 SQL 比较还涵盖未过滤页面、过滤页面和图形聚合,并在同一事务快照中比较结果。放置 JavaScript 测试验证了跨多个屏幕宽度的行为。

测试实例上另一组十五对配对测量显示,筛选和聚合路径分别有约 0.34 ms 和 0.16 ms 的小幅中位开销。我们将这些结果纳入评估:修复并不会让所有场景都更快。这些针对性检查不能替代完整的产品测试套件。

在另一页上重做诊断

首先区分三个问题:服务器需要多长时间准备响应、文档需要多长时间才能到达以及浏览器需要多长时间才能完成加载?

然后计算请求并衡量每一个。对于占主导地位的计划,比较之前/之后的计划以及结果的平等性。特别检查搜索的条目数、中间结果以及索引的有效使用。重复测量:单次观察可能会产生误导。

在这种情况下,查询仍然是查询,并且索引保持不变。查找已存在于缓存中的绘图的方式已发生变化。

详细数据和SQL

  • 16 个查询、它们在代码中的位置以及之前/之后的完整 SQL
  • 十个检测负载:CSV 中每个请求的持续时间
  • 10 月 10 日从服务器发起的 20 次 Chromium 加载,CSV 格式
  • 10 月 10 日的 HTTP curl 检查:修复前和修复后
  • 10 月 10 日测试实例上的 SQL 比较:JSON 格式的结果和计划
  • 来自客户端的匿名 SQL 语句:16 个查询、范围和计划
  • 测试实例的匿名 MariaDB .cnf 配置 和 活动变量、版本和包含文件
  • SVG 中 16 个表的架构、SQL 定义、CSV 中的引擎和大小清单 和JSON 中的列、索引和关系
  • SQL 脚本,以文本形式提供、Chromium 脚本、HTTP 脚本 和 临时 HTTPS 服务器配置
  • 重现10月10日活动的方法和步骤
  • 存档:10 月 9 日连接不稳定的三个生产负载

会话和帐户 ID 由可下载示例中的参数替换。生产和测试测量是分开的,以便在不混合两个环境的情况下对其进行解释。

分享 X LinkedIn Facebook Email PDF
← 返回博客

评论 (0)

暂无评论。

发表评论

使用 Ctrl+V(Mac 上为 Cmd+V)粘贴截图或选择图片。

最多 3 张图片,每张不超过 2 MiB。

PmaControl
+33 6 63 28 27 47 contact@pmacontrol.com
法律声明 GitHub 联系我们
不要等到故障发生才了解您的架构。 © 2014-2026 PmaControl — 68Koncept