Skip to content

Conversation

@lance6716
Copy link
Contributor

@lance6716 lance6716 commented Jan 23, 2026

What problem does this PR solve?

Issue Number: close #65739

Problem Summary:

What changed and how does it work?

check limit and break earlier in slow log executor. In order to do it, need to implement a TopN push down rule for memory table operator.

This PR is mainly written by codex, I also reviewed it roughly before remove [WIP] flag.

Check List

Tests

  • Unit test
  • Integration test
  • Manual test (add detailed scripts or steps below)
  • No need to test
    • I checked and no code files have been changed.

in a 1000 * 300MB slow log files environment:

before this PR

[root@10-2-12-124 slow-log-test]# time mysql --comments --host 127.0.0.1 --port 6716 -u root -e "SELECT Digest, Query, Conn_ID, (UNIX_TIMESTAMP(Time) + 0E0) AS timestamp, Query_time, Mem_max FROM INFORMATION_SCHEMA.CLUSTER_SLOW_QUERY WHERE Time BETWEEN FROM_UNIXTIME(1769103581) AND FROM_UNIXTIME(1769103583) ORDER BY Time DESC LIMIT 100" > /dev/null

real	0m0.566s
user	0m0.007s
sys	0m0.006s

after this PR

[root@10-2-12-124 slow-log-test]# time mysql --comments --host 127.0.0.1 --port 6716 -u root -e "SELECT Digest, Query, Conn_ID, (UNIX_TIMESTAMP(Time) + 0E0) AS timestamp, Query_time, Mem_max FROM INFORMATION_SCHEMA.CLUSTER_SLOW_QUERY WHERE Time BETWEEN FROM_UNIXTIME(1769103581) AND FROM_UNIXTIME(1769103583) ORDER BY Time DESC LIMIT 100" > /dev/null

real	0m0.048s
user	0m0.010s
sys	0m0.004s

Side effects

  • Performance regression: Consumes more CPU
  • Performance regression: Consumes more Memory
  • Breaking backward compatibility

Documentation

  • Affects user behaviors
  • Contains syntax changes
  • Contains variable changes
  • Contains experimental features
  • Changes MySQL compatibility

Release note

Please refer to Release Notes Language Style Guide to write a quality release note.

None

Copilot AI review requested due to automatic review settings January 23, 2026 01:46
@ti-chi-bot ti-chi-bot bot added release-note-none Denotes a PR that doesn't merit a release note. do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Jan 23, 2026
Signed-off-by: lance6716 <lance6716@gmail.com>
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to improve slow log query efficiency by pushing down LIMIT/TopN hints into the slow log memtable executor/retriever so it can stop scanning earlier (especially for dashboard-style queries ordering by time).

Changes:

  • Add row-limit and descending-order hint interfaces for memtable extractors, and implement them in SlowQueryExtractor.
  • Push down TopN/LIMIT hints to slow log memtable plans (logical plan and PB plan builder paths).
  • Refactor slow log reverse scanning and add tests verifying limit pushdown and reverse-scan behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
pkg/util/util.go Splits line-reading into borrowed vs non-aliased variants (ReadLine vs ReadLineCopy) and updates multi-line reads accordingly.
pkg/util/stmtsummary/v2/reader.go Switches statement-summary reader to use non-aliased line reads.
pkg/planner/core/base/misc_base.go Introduces optional memtable extractor hint interfaces (row limit, desc).
pkg/planner/core/memtable_predicate_extractor.go Adds Limit hint + setters to SlowQueryExtractor.
pkg/planner/core/operator/logicalop/logical_mem_table.go Pushes down TopN/LIMIT/desc hints for slow log memtables during logical optimization.
pkg/planner/core/pb_to_plan.go Attempts to propagate LIMIT hint into slow log extractor when building plans from protobuf executors.
pkg/executor/builder.go Wires extractor’s limit hint into the slow-query retriever.
pkg/executor/slow_query.go Adds limit-aware parsing and a new reverse scanner implementation for slow log reading.
pkg/executor/slow_query_test.go Adds coverage for reverse scan with limit and PB plan builder limit pushdown.
Comments suppressed due to low confidence (1)

pkg/executor/slow_query.go:719

  • After publishing an error to taskList, parseSlowLog continues the loop. If the caller stops consuming taskList after receiving the error (without canceling the context), the producer goroutine can block on further sends and leak. Return immediately after e.sendParsedSlowLogCh(..., err) (consistent with other parsing paths).
		if err != nil {
			t := slowLogTask{}
			t.resultCh = make(chan parsedSlowLog, 1)
			select {
			case <-ctx.Done():

Comment on lines +100 to +107
if memTable, ok := p.Children()[0].(*physicalop.PhysicalMemTable); ok {
if extractor, ok := memTable.Extractor.(*SlowQueryExtractor); ok {
end := limit.Offset + limit.Count
if end < limit.Offset {
end = ^uint64(0)
}
extractor.SetRowLimitHint(end)
}
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The limit hint is only applied when the limit’s direct child is *PhysicalMemTable. In PBPlanBuilder, TypeSelection can sit between TableScan and Limit and later be removed by predicatePushDown, so this check can miss and the hint won’t be set for queries with WHERE. Consider walking down unary children to find the underlying memtable (or applying the hint after predicatePushDown).

Suggested change
if memTable, ok := p.Children()[0].(*physicalop.PhysicalMemTable); ok {
if extractor, ok := memTable.Extractor.(*SlowQueryExtractor); ok {
end := limit.Offset + limit.Count
if end < limit.Offset {
end = ^uint64(0)
}
extractor.SetRowLimitHint(end)
}
// Walk down unary children to find the underlying memtable. In PBPlanBuilder,
// operators like TypeSelection can sit between Limit and MemTable and may
// later be removed by predicatePushDown, so checking only the direct child
// can miss and the hint won't be set for queries with WHERE.
child := p.Children()[0]
for child != nil {
if memTable, ok := child.(*physicalop.PhysicalMemTable); ok {
if extractor, ok := memTable.Extractor.(*SlowQueryExtractor); ok {
end := limit.Offset + limit.Count
if end < limit.Offset {
end = ^uint64(0)
}
extractor.SetRowLimitHint(end)
}
break
}
children := child.Children()
if len(children) != 1 {
break
}
child = children[0]

Copilot uses AI. Check for mistakes.
@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

❌ Patch coverage is 80.11050% with 72 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.7545%. Comparing base (e705836) to head (0e591ed).
⚠️ Report is 26 commits behind head on master.

Additional details and impacted files
@@               Coverage Diff                @@
##             master     #65740        +/-   ##
================================================
+ Coverage   77.7867%   78.7545%   +0.9677%     
================================================
  Files          1996       1925        -71     
  Lines        544730     542318      -2412     
================================================
+ Hits         423728     427100      +3372     
+ Misses       119343     114811      -4532     
+ Partials       1659        407      -1252     
Flag Coverage Δ
integration 44.3298% <34.7222%> (-3.8499%) ⬇️
unit 77.3844% <79.5580%> (+0.9711%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
dumpling 56.7974% <ø> (ø)
parser ∅ <ø> (∅)
br 49.4378% <ø> (-11.6028%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@tiprow
Copy link

tiprow bot commented Jan 23, 2026

Hi @lance6716. Thanks for your PR.

PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test all.

I understand the commands that are listed here.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Signed-off-by: lance6716 <lance6716@gmail.com>
Signed-off-by: lance6716 <lance6716@gmail.com>
Signed-off-by: lance6716 <lance6716@gmail.com>
Copilot AI review requested due to automatic review settings January 23, 2026 04:32
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

extractor.SetRowLimitHint(end)
}
}
}
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pushdown currently only handles PhysicalLimit. For ORDER BY ... LIMIT queries, the DAG commonly uses TopN (tipb.ExecType_TypeTopN -> PhysicalTopN), so SlowQueryExtractor.Limit won’t be set in that case. Consider applying the same (offset+count) row-limit hint when building PhysicalTopN as well, so the optimization works for the dashboard query pattern.

Suggested change
}
}
if topN, ok := p.(*physicalop.PhysicalTopN); ok {
if memTable, ok := p.Children()[0].(*physicalop.PhysicalMemTable); ok {
if extractor, ok := memTable.Extractor.(*SlowQueryExtractor); ok {
end := topN.Offset + topN.Count
if end < topN.Offset {
end = ^uint64(0)
}
extractor.SetRowLimitHint(end)
}
}
}

Copilot uses AI. Check for mistakes.
Comment on lines 532 to 575
func (s *slowLogReverseScanner) loadCompressedBlocks(ctx context.Context, file *os.File) error {
_, err := file.Seek(0, io.SeekStart)
if err != nil {
return err
}
gr, err := gzip.NewReader(file)
if err != nil {
return err
}
defer func() { _ = gr.Close() }()

reader := bufio.NewReader(gr)
blocks := make([]slowLogBlock, 0)
var (
block slowLogBlock
hasStartFlag bool
)
for {
if isCtxDone(ctx) {
return ctx.Err()
}
lineByte, err := getOneLine(reader)
if err != nil {
if err == io.EOF {
if len(log) == 0 {
decomposedSlowLogTasks := decomposeToSlowLogTasks(logs, num)
offset.length = len(decomposedSlowLogTasks)
return decomposedSlowLogTasks, nil
}
e.fileLine = 0
reader, err = e.getPreviousReader()
if reader == nil || err != nil {
return decomposeToSlowLogTasks(logs, num), nil
if len(block) > 0 {
blocks = append(blocks, block)
}
scanPreviousFile = true
continue
s.compressedBlocks = blocks
return nil
}
return nil, err
return err
}
line = string(hack.String(lineByte))
line := string(hack.String(lineByte))
if !hasStartFlag && strings.HasPrefix(line, variable.SlowLogStartPrefixStr) {
hasStartFlag = true
}
if hasStartFlag {
log = append(log, line)
block = append(block, line)
if strings.HasSuffix(line, variable.SlowLogSQLSuffixStr) {
if strings.HasPrefix(line, "use") || strings.HasPrefix(line, variable.SlowLogRowPrefixStr) {
continue
}
logs = append(logs, log)
if scanPreviousFile {
break
}
log = make([]string, 0, 8)
blocks = append(blocks, block)
block = make(slowLogBlock, 0, 8)
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadCompressedBlocks decompresses and materializes all slow-log blocks from a .gz file into memory (blocks / s.compressedBlocks). For large rotated slow logs this can be very memory-intensive and defeats the benefit of a small LIMIT hint. Consider streaming and keeping only the last N blocks needed (e.g. based on maxBlocks/e.limit) instead of storing every block, or otherwise bounding memory usage.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leave a TODO

Signed-off-by: lance6716 <lance6716@gmail.com>
Signed-off-by: lance6716 <lance6716@gmail.com>
Copilot AI review requested due to automatic review settings January 23, 2026 06:16
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Signed-off-by: lance6716 <lance6716@gmail.com>
Signed-off-by: lance6716 <lance6716@gmail.com>
Copilot AI review requested due to automatic review settings January 23, 2026 06:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Comment on lines +626 to +629
if e.limit > 0 {
e.parseSlowLogByBatchGetterWithLimit(ctx, sctx, batchSize, off, nextBatch, afterBatch)
return
}
Copy link

Copilot AI Jan 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseSlowLogByBatchGetter switches to a fully-serial parsing path whenever e.limit > 0. Because limit hints are now pushed down for normal LIMIT queries too, this can reduce throughput for large limits (e.g. exporting many slow logs) compared to the concurrent path. Consider keeping concurrency when the limit is large (or when early-exit is unlikely), or gating the serial path behind a small-limit threshold.

Copilot uses AI. Check for mistakes.
@lance6716
Copy link
Contributor Author

/hold

failed CI shows there's a correctness problem

@ti-chi-bot ti-chi-bot bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 23, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@lance6716

This comment was marked as outdated.

Signed-off-by: lance6716 <lance6716@gmail.com>
@lance6716
Copy link
Contributor Author

/unhold

@ti-chi-bot ti-chi-bot bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 23, 2026
@ti-chi-bot ti-chi-bot bot added approved needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jan 26, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 27, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: crazycs520, hawkingrei

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@ti-chi-bot ti-chi-bot bot added lgtm and removed needs-1-more-lgtm Indicates a PR needs 1 more LGTM. labels Jan 27, 2026
@ti-chi-bot
Copy link

ti-chi-bot bot commented Jan 27, 2026

[LGTM Timeline notifier]

Timeline:

  • 2026-01-26 09:52:29.023045963 +0000 UTC m=+1005976.637002819: ☑️ agreed by hawkingrei.
  • 2026-01-27 02:42:09.817303907 +0000 UTC m=+1066557.431260764: ☑️ agreed by crazycs520.

@lance6716
Copy link
Contributor Author

lance6716 commented Jan 27, 2026

/hold

I'll check test coverage soon

@ti-chi-bot ti-chi-bot bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 27, 2026
@lance6716
Copy link
Contributor Author

/unhold

@ti-chi-bot ti-chi-bot bot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 27, 2026
@lance6716
Copy link
Contributor Author

/retest

@tiprow
Copy link

tiprow bot commented Jan 27, 2026

@lance6716: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@lance6716
Copy link
Contributor Author

/retest

@tiprow
Copy link

tiprow bot commented Jan 28, 2026

@lance6716: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@lance6716
Copy link
Contributor Author

/retest

@tiprow
Copy link

tiprow bot commented Jan 28, 2026

@lance6716: PRs from untrusted users cannot be marked as trusted with /ok-to-test in this repo meaning untrusted PR authors can never trigger tests themselves. Collaborators can still trigger tests on the PR using /test.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@ti-chi-bot ti-chi-bot bot merged commit 39856f6 into pingcap:master Jan 28, 2026
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved lgtm release-note-none Denotes a PR that doesn't merit a release note. sig/planner SIG: Planner size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support pushing down limit to slow log executor

3 participants