From c23ae47071f31a18b927ea8e0d14dea9625735c9 Mon Sep 17 00:00:00 2001 From: lukasz-stec Date: Sat, 15 Feb 2025 11:38:32 +0100 Subject: [PATCH] Print splits count and distribution time in EXPLAIN ANALYZE Split distribution time can be a bottleneck in some scenarios. Having it in the EXPLAIN output makes it easier to diagnose without accessing query json. Split count is helpful to analyze query performance when there is either a big number of small splits or there is just one split like with basic JDBC connectors. The split count is visible also in the "Input rows distribution" metric but it is only available in the VERBOSE mode. --- .../io/trino/sql/planner/planprinter/PlanPrinter.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java b/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java index 589e97e7fa7d..f62c4362228c 100644 --- a/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java +++ b/core/trino-main/src/main/java/io/trino/sql/planner/planprinter/PlanPrinter.java @@ -507,6 +507,10 @@ private static String formatFragment( stageStats.getPeakUserMemoryReservation().succinct(), tasks.size(), maxPeakTaskMemoryUsage.succinct())); + if (stageStats.getGetSplitDistribution().getTotal() > 0) { + builder.append(indentString(1)) + .append(format("Total split distribution time: %sms\n", formatDouble(stageStats.getGetSplitDistribution().getTotal() / 1_000_000))); + } Optional outputBufferUtilization = stageInfo.get().getStageStats().getOutputBufferUtilization(); if (verbose && outputBufferUtilization.isPresent()) { builder.append(indentString(1)) @@ -1146,6 +1150,7 @@ public Void visitTableScan(TableScanNode node, Context context) formatPositions(nodeStats.getPlanNodeInputPositions()), nodeStats.getPlanNodeInputDataSize().toString()); addPhysicalInputStats(nodeStats, inputDetailBuilder, argsBuilder); + addSplits(nodeStats, inputDetailBuilder, argsBuilder); appendDetailsFromBuilder(nodeOutput, inputDetailBuilder, argsBuilder); } return null; @@ -1280,6 +1285,7 @@ private Void visitScanFilterAndProjectInfo( nodeStats.getPlanNodeInputDataSize().toString(), formatDouble(filtered)); addPhysicalInputStats(nodeStats, inputDetailBuilder, argsBuilder); + addSplits(nodeStats, inputDetailBuilder, argsBuilder); appendDetailsFromBuilder(nodeOutput, inputDetailBuilder, argsBuilder); } List collectedDomainStats = dynamicFilters.stream() @@ -1310,6 +1316,11 @@ private Void visitScanFilterAndProjectInfo( return null; } + private void addSplits(PlanNodeStats nodeStats, StringBuilder inputDetailBuilder, ImmutableList.Builder argsBuilder) + { + buildFormatString(inputDetailBuilder, argsBuilder, ", Splits: %s", String.valueOf(nodeStats.getOperatorStats().values().iterator().next().getTotalDrivers())); + } + private static void addPhysicalInputStats(PlanNodeStats nodeStats, StringBuilder inputDetailBuilder, ImmutableList.Builder argsBuilder) { if (nodeStats.getPlanNodePhysicalInputDataSize().toBytes() > 0) {