1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-38019 Send ok packet to client earlier

Send ok packet earlier for SELECT queries that does not have any updates.
This is done in select_send::send_eof()

Axel's select benchmarks shows that this has a notable speed improvement:
1  Thread:  28% TPS speedup
8  Threads: 23%
64 Threads  6%

This was meassured with t_oltp_point_select With InnoDB running the client
over sockets.

Other things:
- Moved error reporting of LIMIT ROWS EXAMINED from handle_select() to
  check_limit_rows_examined(). This is to ensure that the error is
  reported before send_eof() is called.
- Removed duplicate "Query execution was interrupted" messages for the
  same query. killed_for_exceeding_limit_rows_warning_given was introduced
  for this purpose. We cannot use 'killed' flag in
  killed_for_exceeding_limit_rows() to detect if we already have produced
  a warning as the 'killed' in this case is reset for each union.

Reviewer: Sergei Golubchik <serg@mariadb.org>
This commit is contained in:
Monty
2025-11-04 22:29:47 +02:00
parent 366de0ae3b
commit 0513a4a974
8 changed files with 123 additions and 88 deletions

View File

@@ -773,7 +773,6 @@ LIMIT ROWS EXAMINED 124;
field1 field2 field3 field4 field5
Warnings:
Warning 1931 Query execution was interrupted. The query exceeded LIMIT ROWS EXAMINED 124. The query result may be incomplete
Warning 1931 Query execution was interrupted. The query exceeded LIMIT ROWS EXAMINED 124. The query result may be incomplete
SHOW STATUS LIKE 'Handler_read%';
Variable_name Value
Handler_read_first 1

View File

@@ -125,15 +125,15 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
8 8 stage/sql/After opening tables (stage) STATEMENT 0
9 9 stage/sql/init (stage) STATEMENT 0
10 10 stage/sql/Optimizing (stage) STATEMENT 0
11 11 stage/sql/Executing (stage) STATEMENT 0
12 12 stage/sql/End of update loop (stage) STATEMENT 0
13 14 stage/sql/Query end (stage) STATEMENT 0
14 14 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 13
15 15 stage/sql/closing tables (stage) STATEMENT 0
16 16 stage/sql/Query end (stage) STATEMENT 0
17 17 stage/sql/Starting cleanup (stage) STATEMENT 0
18 18 stage/sql/Freeing items (stage) STATEMENT 0
19 19 wait/io/socket/sql/client_connection send STATEMENT 0
11 12 stage/sql/Executing (stage) STATEMENT 0
12 12 wait/io/socket/sql/client_connection send STAGE 11
13 13 stage/sql/End of update loop (stage) STATEMENT 0
14 15 stage/sql/Query end (stage) STATEMENT 0
15 15 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 14
16 16 stage/sql/closing tables (stage) STATEMENT 0
17 17 stage/sql/Query end (stage) STATEMENT 0
18 18 stage/sql/Starting cleanup (stage) STATEMENT 0
19 19 stage/sql/Freeing items (stage) STATEMENT 0
20 21 stage/sql/Reset for next command (stage) STATEMENT 0
21 21 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 20
22 22 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 0
@@ -149,15 +149,15 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
32 32 stage/sql/After opening tables (stage) STATEMENT 24
33 33 stage/sql/init (stage) STATEMENT 24
34 34 stage/sql/Optimizing (stage) STATEMENT 24
35 35 stage/sql/Executing (stage) STATEMENT 24
36 36 stage/sql/End of update loop (stage) STATEMENT 24
37 38 stage/sql/Query end (stage) STATEMENT 24
38 38 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 37
39 39 stage/sql/closing tables (stage) STATEMENT 24
40 40 stage/sql/Query end (stage) STATEMENT 24
41 41 stage/sql/Starting cleanup (stage) STATEMENT 24
42 42 stage/sql/Freeing items (stage) STATEMENT 24
43 43 wait/io/socket/sql/client_connection send STATEMENT 24
35 36 stage/sql/Executing (stage) STATEMENT 24
36 36 wait/io/socket/sql/client_connection send STAGE 35
37 37 stage/sql/End of update loop (stage) STATEMENT 24
38 39 stage/sql/Query end (stage) STATEMENT 24
39 39 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 38
40 40 stage/sql/closing tables (stage) STATEMENT 24
41 41 stage/sql/Query end (stage) STATEMENT 24
42 42 stage/sql/Starting cleanup (stage) STATEMENT 24
43 43 stage/sql/Freeing items (stage) STATEMENT 24
44 45 stage/sql/Reset for next command (stage) STATEMENT 24
45 45 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 44
46 46 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 24
@@ -173,15 +173,15 @@ relative_event_id relative_end_event_id event_name comment nesting_event_type re
56 56 stage/sql/After opening tables (stage) STATEMENT 48
57 57 stage/sql/init (stage) STATEMENT 48
58 58 stage/sql/Optimizing (stage) STATEMENT 48
59 59 stage/sql/Executing (stage) STATEMENT 48
60 60 stage/sql/End of update loop (stage) STATEMENT 48
61 62 stage/sql/Query end (stage) STATEMENT 48
62 62 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 61
63 63 stage/sql/closing tables (stage) STATEMENT 48
64 64 stage/sql/Query end (stage) STATEMENT 48
65 65 stage/sql/Starting cleanup (stage) STATEMENT 48
66 66 stage/sql/Freeing items (stage) STATEMENT 48
67 67 wait/io/socket/sql/client_connection send STATEMENT 48
59 60 stage/sql/Executing (stage) STATEMENT 48
60 60 wait/io/socket/sql/client_connection send STAGE 59
61 61 stage/sql/End of update loop (stage) STATEMENT 48
62 63 stage/sql/Query end (stage) STATEMENT 48
63 63 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 62
64 64 stage/sql/closing tables (stage) STATEMENT 48
65 65 stage/sql/Query end (stage) STATEMENT 48
66 66 stage/sql/Starting cleanup (stage) STATEMENT 48
67 67 stage/sql/Freeing items (stage) STATEMENT 48
68 69 stage/sql/Reset for next command (stage) STATEMENT 48
69 69 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 68
70 70 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 48
@@ -200,15 +200,15 @@ select "With a third part to make things complete" as payload NULL NULL
81 81 stage/sql/After opening tables (stage) STATEMENT 72
82 82 stage/sql/init (stage) STATEMENT 72
83 83 stage/sql/Optimizing (stage) STATEMENT 72
84 84 stage/sql/Executing (stage) STATEMENT 72
85 85 stage/sql/End of update loop (stage) STATEMENT 72
86 87 stage/sql/Query end (stage) STATEMENT 72
87 87 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 86
88 88 stage/sql/closing tables (stage) STATEMENT 72
89 89 stage/sql/Query end (stage) STATEMENT 72
90 90 stage/sql/Starting cleanup (stage) STATEMENT 72
91 92 stage/sql/Freeing items (stage) STATEMENT 72
92 92 wait/io/socket/sql/client_connection send STAGE 91
84 85 stage/sql/Executing (stage) STATEMENT 72
85 85 wait/io/socket/sql/client_connection send STAGE 84
86 86 stage/sql/End of update loop (stage) STATEMENT 72
87 88 stage/sql/Query end (stage) STATEMENT 72
88 88 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 87
89 89 stage/sql/closing tables (stage) STATEMENT 72
90 90 stage/sql/Query end (stage) STATEMENT 72
91 91 stage/sql/Starting cleanup (stage) STATEMENT 72
92 92 stage/sql/Freeing items (stage) STATEMENT 72
93 110 statement/sql/select select "And this is the second part of a multi query" as payload;
select "With a third part to make things complete" as payload NULL NULL
94 96 stage/sql/starting (stage) STATEMENT 93
@@ -219,15 +219,15 @@ select "With a third part to make things complete" as payload NULL NULL
99 99 stage/sql/After opening tables (stage) STATEMENT 93
100 100 stage/sql/init (stage) STATEMENT 93
101 101 stage/sql/Optimizing (stage) STATEMENT 93
102 102 stage/sql/Executing (stage) STATEMENT 93
103 103 stage/sql/End of update loop (stage) STATEMENT 93
104 105 stage/sql/Query end (stage) STATEMENT 93
105 105 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 104
106 106 stage/sql/closing tables (stage) STATEMENT 93
107 107 stage/sql/Query end (stage) STATEMENT 93
108 108 stage/sql/Starting cleanup (stage) STATEMENT 93
109 110 stage/sql/Freeing items (stage) STATEMENT 93
110 110 wait/io/socket/sql/client_connection send STAGE 109
102 103 stage/sql/Executing (stage) STATEMENT 93
103 103 wait/io/socket/sql/client_connection send STAGE 102
104 104 stage/sql/End of update loop (stage) STATEMENT 93
105 106 stage/sql/Query end (stage) STATEMENT 93
106 106 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 105
107 107 stage/sql/closing tables (stage) STATEMENT 93
108 108 stage/sql/Query end (stage) STATEMENT 93
109 109 stage/sql/Starting cleanup (stage) STATEMENT 93
110 110 stage/sql/Freeing items (stage) STATEMENT 93
111 129 statement/sql/select select "With a third part to make things complete" as payload NULL NULL
112 113 stage/sql/starting (stage) STATEMENT 111
113 113 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 112
@@ -236,15 +236,15 @@ select "With a third part to make things complete" as payload NULL NULL
116 116 stage/sql/After opening tables (stage) STATEMENT 111
117 117 stage/sql/init (stage) STATEMENT 111
118 118 stage/sql/Optimizing (stage) STATEMENT 111
119 119 stage/sql/Executing (stage) STATEMENT 111
120 120 stage/sql/End of update loop (stage) STATEMENT 111
121 122 stage/sql/Query end (stage) STATEMENT 111
122 122 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 121
123 123 stage/sql/closing tables (stage) STATEMENT 111
124 124 stage/sql/Query end (stage) STATEMENT 111
125 125 stage/sql/Starting cleanup (stage) STATEMENT 111
126 126 stage/sql/Freeing items (stage) STATEMENT 111
127 127 wait/io/socket/sql/client_connection send STATEMENT 111
119 120 stage/sql/Executing (stage) STATEMENT 111
120 120 wait/io/socket/sql/client_connection send STAGE 119
121 121 stage/sql/End of update loop (stage) STATEMENT 111
122 123 stage/sql/Query end (stage) STATEMENT 111
123 123 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 122
124 124 stage/sql/closing tables (stage) STATEMENT 111
125 125 stage/sql/Query end (stage) STATEMENT 111
126 126 stage/sql/Starting cleanup (stage) STATEMENT 111
127 127 stage/sql/Freeing items (stage) STATEMENT 111
128 129 stage/sql/Reset for next command (stage) STATEMENT 111
129 129 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 128
130 130 wait/synch/mutex/sql/THD::LOCK_thd_data lock STATEMENT 111
@@ -260,15 +260,15 @@ select "With a third part to make things complete" as payload NULL NULL
140 140 stage/sql/After opening tables (stage) STATEMENT 132
141 141 stage/sql/init (stage) STATEMENT 132
142 142 stage/sql/Optimizing (stage) STATEMENT 132
143 143 stage/sql/Executing (stage) STATEMENT 132
144 144 stage/sql/End of update loop (stage) STATEMENT 132
145 146 stage/sql/Query end (stage) STATEMENT 132
146 146 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 145
147 147 stage/sql/closing tables (stage) STATEMENT 132
148 148 stage/sql/Query end (stage) STATEMENT 132
149 149 stage/sql/Starting cleanup (stage) STATEMENT 132
150 150 stage/sql/Freeing items (stage) STATEMENT 132
151 151 wait/io/socket/sql/client_connection send STATEMENT 132
143 144 stage/sql/Executing (stage) STATEMENT 132
144 144 wait/io/socket/sql/client_connection send STAGE 143
145 145 stage/sql/End of update loop (stage) STATEMENT 132
146 147 stage/sql/Query end (stage) STATEMENT 132
147 147 wait/synch/mutex/sql/THD::LOCK_thd_kill lock STAGE 146
148 148 stage/sql/closing tables (stage) STATEMENT 132
149 149 stage/sql/Query end (stage) STATEMENT 132
150 150 stage/sql/Starting cleanup (stage) STATEMENT 132
151 151 stage/sql/Freeing items (stage) STATEMENT 132
152 153 stage/sql/Reset for next command (stage) STATEMENT 132
153 153 wait/synch/mutex/sql/THD::LOCK_thd_data lock STAGE 152
disconnect con1;

View File

@@ -580,10 +580,9 @@ void Protocol::end_statement()
#endif /* WITH_WSREP */
DBUG_ENTER("Protocol::end_statement");
DBUG_ASSERT(! thd->get_stmt_da()->is_sent());
bool error= FALSE;
/* Can not be true, but do not take chances in production. */
/* This can set in the case of early result sent by select_send::send_eof() */
if (thd->get_stmt_da()->is_sent())
DBUG_VOID_RETURN;

View File

@@ -884,6 +884,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
net.reading_or_writing= 0;
client_capabilities= 0; // minimalistic client
system_thread= NON_SYSTEM_THREAD;
killed_for_exceeding_limit_rows_warning_given= 0;
shared_thd= 0;
cleanup_done= free_connection_done= abort_on_warning= got_warning= 0;
peer_port= 0; // For SHOW PROCESSLIST
@@ -2358,6 +2359,32 @@ void THD::reset_killed()
DBUG_VOID_RETURN;
}
/*
Mark query killed for exceeding limit rows
The current select will be aborted, but the incomplete result set will
be sent to the user
*/
void THD::killed_for_exceeding_limit_rows()
{
set_killed(ABORT_QUERY);
if (!no_errors && !killed_for_exceeding_limit_rows_warning_given)
{
killed_for_exceeding_limit_rows_warning_given= 1;
bool saved_abort_on_warning= abort_on_warning;
abort_on_warning= false;
push_warning_printf(this, Sql_condition::WARN_LEVEL_WARN,
ER_QUERY_RESULT_INCOMPLETE,
ER_THD(this, ER_QUERY_RESULT_INCOMPLETE),
"LIMIT ROWS EXAMINED",
lex->limit_rows_examined->val_uint());
abort_on_warning= saved_abort_on_warning;
}
}
/*
Remember the location of thread info, the structure needed for
the structure for the net buffer
@@ -3371,13 +3398,34 @@ int select_send::send_data(List<Item> &items)
bool select_send::send_eof()
{
/*
/*
Don't send EOF if we're in error condition (which implies we've already
sent or are sending an error)
*/
if (unlikely(thd->is_error()))
{
reset_for_next_ps_execution();
return TRUE;
}
::my_eof(thd);
if (unlikely(thd->lex->sql_command != SQLCOM_SELECT))
goto end; // For DELETE RETURNING
if (likely(!thd->transaction->stmt.is_trx_read_write()))
{
/*
We are executing a readonly statement. Send the result to the
client so that it can process the data while the server is doing
cleanups.
*/
thd->push_final_warnings();
thd->update_server_status(); // Needed for slow query status
thd->protocol->end_statement();
}
end:
reset_for_next_ps_execution();
return FALSE;
}
@@ -4679,7 +4727,6 @@ bool select_dumpvar::send_eof()
}
bool
select_materialize_with_stats::
create_result_table(THD *thd_arg, List<Item> *column_types,

View File

@@ -3403,6 +3403,7 @@ public:
must be reset (all items be removed from it).
*/
bool reset_sp_cache;
bool killed_for_exceeding_limit_rows_warning_given;
/* container for handler's private per-connection data */
Ha_data ha_data[MAX_HA];
@@ -4010,10 +4011,11 @@ public:
Check if the number of rows accessed by a statement exceeded
LIMIT ROWS EXAMINED. If so, signal the query engine to stop execution.
*/
void killed_for_exceeding_limit_rows();
inline void check_limit_rows_examined()
{
if (++accessed_rows_and_keys > lex->limit_rows_examined_cnt)
set_killed(ABORT_QUERY);
killed_for_exceeding_limit_rows();
}
USER_CONN *user_connect;

View File

@@ -655,21 +655,16 @@ bool handle_select(THD *thd, LEX *lex, select_result *result,
if (unlikely(thd->killed == ABORT_QUERY && !thd->no_errors))
{
/*
If LIMIT ROWS EXAMINED interrupted query execution, issue a warning,
continue with normal processing and produce an incomplete query result.
If LIMIT ROWS EXAMINED interrupted query execution
continue with normal processing and produce an incomplete query
result.
A warning was generated by killed_for_exceeding_limit_rows().
*/
bool saved_abort_on_warning= thd->abort_on_warning;
thd->abort_on_warning= false;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_QUERY_RESULT_INCOMPLETE,
ER_THD(thd, ER_QUERY_RESULT_INCOMPLETE),
"LIMIT ROWS EXAMINED",
thd->lex->limit_rows_examined->val_uint());
thd->abort_on_warning= saved_abort_on_warning;
thd->reset_killed();
}
/* Deactivate LIMIT ROWS EXAMINED after query execution. */
thd->lex->deactivate_limit_rows_examined();
thd->killed_for_exceeding_limit_rows_warning_given= 0;
MYSQL_SELECT_DONE((int) res, (ulong) thd->limit_found_rows);
DBUG_RETURN(res);

View File

@@ -2518,11 +2518,6 @@ bool st_select_lex_unit::exec_inner()
Stop execution of the remaining queries in the UNIONS, and produce
the current result.
*/
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_QUERY_RESULT_INCOMPLETE,
ER_THD(thd, ER_QUERY_RESULT_INCOMPLETE),
"LIMIT ROWS EXAMINED",
thd->lex->limit_rows_examined->val_uint());
thd->reset_killed();
break;
}

View File

@@ -3013,11 +3013,9 @@ int ha_maria::external_lock(THD *thd, int lock_type)
!trnman_decrement_locked_tables(trn))
{
/*
OK should not have been sent to client yet (ACID).
This is a bit excessive, ACID requires this only if there are some
changes to commit (rollback shouldn't be tested).
OK should not have been sent to client in case of write (ACID).
*/
DBUG_ASSERT(!thd->get_stmt_da()->is_sent() ||
DBUG_ASSERT(!trn->undo_lsn || !thd->get_stmt_da()->is_sent() ||
thd->killed);
/*
If autocommit, commit transaction. This can happen when open and