Merge pull request #11236 from HJianBo/perf-speedup-the-empty-conds-query
perf(http): improve the speed of clients querying in default parameters
This commit is contained in:
commit
515b414d99
|
@ -29,7 +29,9 @@
|
||||||
%% first_next query APIs
|
%% first_next query APIs
|
||||||
-export([
|
-export([
|
||||||
node_query/6,
|
node_query/6,
|
||||||
|
node_query/7,
|
||||||
cluster_query/5,
|
cluster_query/5,
|
||||||
|
cluster_query/6,
|
||||||
b2i/1
|
b2i/1
|
||||||
]).
|
]).
|
||||||
|
|
||||||
|
@ -57,6 +59,18 @@
|
||||||
fun((node(), term()) -> term())
|
fun((node(), term()) -> term())
|
||||||
| fun((term()) -> term()).
|
| fun((term()) -> term()).
|
||||||
|
|
||||||
|
-type query_options() :: #{
|
||||||
|
%% Whether to use `ets:info/2` to get the total number of rows when the query conditions are
|
||||||
|
%% empty. It can significantly improves the speed of the query when the table stored large
|
||||||
|
%% amounts of data.
|
||||||
|
%%
|
||||||
|
%% However, it may cause the total number of rows to be inaccurate when the table stored in
|
||||||
|
%% multiple schemas of data, i.e: Built-in Authorization
|
||||||
|
%%
|
||||||
|
%% Default: false
|
||||||
|
fast_total_counting => boolean()
|
||||||
|
}.
|
||||||
|
|
||||||
-type query_return() :: #{meta := map(), data := [term()]}.
|
-type query_return() :: #{meta := map(), data := [term()]}.
|
||||||
|
|
||||||
-export([do_query/2, apply_total_query/1]).
|
-export([do_query/2, apply_total_query/1]).
|
||||||
|
@ -114,13 +128,25 @@ limit(Params) when is_map(Params) ->
|
||||||
format_result_fun()
|
format_result_fun()
|
||||||
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
||||||
node_query(Node, Tab, QString, QSchema, MsFun, FmtFun) ->
|
node_query(Node, Tab, QString, QSchema, MsFun, FmtFun) ->
|
||||||
|
node_query(Node, Tab, QString, QSchema, MsFun, FmtFun, #{}).
|
||||||
|
|
||||||
|
-spec node_query(
|
||||||
|
node(),
|
||||||
|
atom(),
|
||||||
|
query_params(),
|
||||||
|
query_schema(),
|
||||||
|
query_to_match_spec_fun(),
|
||||||
|
format_result_fun(),
|
||||||
|
query_options()
|
||||||
|
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
||||||
|
node_query(Node, Tab, QString, QSchema, MsFun, FmtFun, Options) ->
|
||||||
case parse_pager_params(QString) of
|
case parse_pager_params(QString) of
|
||||||
false ->
|
false ->
|
||||||
{error, page_limit_invalid};
|
{error, page_limit_invalid};
|
||||||
Meta ->
|
Meta ->
|
||||||
{_CodCnt, NQString} = parse_qstring(QString, QSchema),
|
{_CodCnt, NQString} = parse_qstring(QString, QSchema),
|
||||||
ResultAcc = init_query_result(),
|
ResultAcc = init_query_result(),
|
||||||
QueryState = init_query_state(Tab, NQString, MsFun, Meta),
|
QueryState = init_query_state(Tab, NQString, MsFun, Meta, Options),
|
||||||
NResultAcc = do_node_query(
|
NResultAcc = do_node_query(
|
||||||
Node, QueryState, ResultAcc
|
Node, QueryState, ResultAcc
|
||||||
),
|
),
|
||||||
|
@ -158,6 +184,17 @@ do_node_query(
|
||||||
format_result_fun()
|
format_result_fun()
|
||||||
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
||||||
cluster_query(Tab, QString, QSchema, MsFun, FmtFun) ->
|
cluster_query(Tab, QString, QSchema, MsFun, FmtFun) ->
|
||||||
|
cluster_query(Tab, QString, QSchema, MsFun, FmtFun, #{}).
|
||||||
|
|
||||||
|
-spec cluster_query(
|
||||||
|
atom(),
|
||||||
|
query_params(),
|
||||||
|
query_schema(),
|
||||||
|
query_to_match_spec_fun(),
|
||||||
|
format_result_fun(),
|
||||||
|
query_options()
|
||||||
|
) -> {error, page_limit_invalid} | {error, atom(), term()} | query_return().
|
||||||
|
cluster_query(Tab, QString, QSchema, MsFun, FmtFun, Options) ->
|
||||||
case parse_pager_params(QString) of
|
case parse_pager_params(QString) of
|
||||||
false ->
|
false ->
|
||||||
{error, page_limit_invalid};
|
{error, page_limit_invalid};
|
||||||
|
@ -165,7 +202,7 @@ cluster_query(Tab, QString, QSchema, MsFun, FmtFun) ->
|
||||||
{_CodCnt, NQString} = parse_qstring(QString, QSchema),
|
{_CodCnt, NQString} = parse_qstring(QString, QSchema),
|
||||||
Nodes = emqx:running_nodes(),
|
Nodes = emqx:running_nodes(),
|
||||||
ResultAcc = init_query_result(),
|
ResultAcc = init_query_result(),
|
||||||
QueryState = init_query_state(Tab, NQString, MsFun, Meta),
|
QueryState = init_query_state(Tab, NQString, MsFun, Meta, Options),
|
||||||
NResultAcc = do_cluster_query(
|
NResultAcc = do_cluster_query(
|
||||||
Nodes, QueryState, ResultAcc
|
Nodes, QueryState, ResultAcc
|
||||||
),
|
),
|
||||||
|
@ -231,9 +268,10 @@ collect_total_from_tail_nodes(Nodes, QueryState = #{total := TotalAcc}) ->
|
||||||
%% table := atom(),
|
%% table := atom(),
|
||||||
%% qs := {Qs, Fuzzy}, %% parsed query params
|
%% qs := {Qs, Fuzzy}, %% parsed query params
|
||||||
%% msfun := query_to_match_spec_fun(),
|
%% msfun := query_to_match_spec_fun(),
|
||||||
%% complete := boolean()
|
%% complete := boolean(),
|
||||||
|
%% options := query_options()
|
||||||
%% }
|
%% }
|
||||||
init_query_state(Tab, QString, MsFun, _Meta = #{page := Page, limit := Limit}) ->
|
init_query_state(Tab, QString, MsFun, _Meta = #{page := Page, limit := Limit}, Options) ->
|
||||||
#{match_spec := Ms, fuzzy_fun := FuzzyFun} = erlang:apply(MsFun, [Tab, QString]),
|
#{match_spec := Ms, fuzzy_fun := FuzzyFun} = erlang:apply(MsFun, [Tab, QString]),
|
||||||
%% assert FuzzyFun type
|
%% assert FuzzyFun type
|
||||||
_ =
|
_ =
|
||||||
|
@ -252,7 +290,8 @@ init_query_state(Tab, QString, MsFun, _Meta = #{page := Page, limit := Limit}) -
|
||||||
msfun => MsFun,
|
msfun => MsFun,
|
||||||
match_spec => Ms,
|
match_spec => Ms,
|
||||||
fuzzy_fun => FuzzyFun,
|
fuzzy_fun => FuzzyFun,
|
||||||
complete => false
|
complete => false,
|
||||||
|
options => Options
|
||||||
},
|
},
|
||||||
case counting_total_fun(QueryState) of
|
case counting_total_fun(QueryState) of
|
||||||
false ->
|
false ->
|
||||||
|
@ -355,6 +394,8 @@ apply_total_query(QueryState = #{table := Tab}) ->
|
||||||
Fun(Tab)
|
Fun(Tab)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
counting_total_fun(_QueryState = #{qs := {[], []}, options := #{fast_total_counting := true}}) ->
|
||||||
|
fun(Tab) -> ets:info(Tab, size) end;
|
||||||
counting_total_fun(_QueryState = #{match_spec := Ms, fuzzy_fun := undefined}) ->
|
counting_total_fun(_QueryState = #{match_spec := Ms, fuzzy_fun := undefined}) ->
|
||||||
%% XXX: Calculating the total number of data that match a certain
|
%% XXX: Calculating the total number of data that match a certain
|
||||||
%% condition under a large table is very expensive because the
|
%% condition under a large table is very expensive because the
|
||||||
|
@ -373,9 +414,7 @@ counting_total_fun(_QueryState = #{match_spec := Ms, fuzzy_fun := undefined}) ->
|
||||||
counting_total_fun(_QueryState = #{fuzzy_fun := FuzzyFun}) when FuzzyFun =/= undefined ->
|
counting_total_fun(_QueryState = #{fuzzy_fun := FuzzyFun}) when FuzzyFun =/= undefined ->
|
||||||
%% XXX: Calculating the total number for a fuzzy searching is very very expensive
|
%% XXX: Calculating the total number for a fuzzy searching is very very expensive
|
||||||
%% so it is not supported now
|
%% so it is not supported now
|
||||||
false;
|
false.
|
||||||
counting_total_fun(_QueryState = #{qs := {[], []}}) ->
|
|
||||||
fun(Tab) -> ets:info(Tab, size) end.
|
|
||||||
|
|
||||||
%% ResultAcc :: #{count := integer(),
|
%% ResultAcc :: #{count := integer(),
|
||||||
%% cursor := integer(),
|
%% cursor := integer(),
|
||||||
|
|
|
@ -661,12 +661,14 @@ list_clients(QString) ->
|
||||||
Result =
|
Result =
|
||||||
case maps:get(<<"node">>, QString, undefined) of
|
case maps:get(<<"node">>, QString, undefined) of
|
||||||
undefined ->
|
undefined ->
|
||||||
|
Options = #{fast_total_counting => true},
|
||||||
emqx_mgmt_api:cluster_query(
|
emqx_mgmt_api:cluster_query(
|
||||||
?CHAN_INFO_TAB,
|
?CHAN_INFO_TAB,
|
||||||
QString,
|
QString,
|
||||||
?CLIENT_QSCHEMA,
|
?CLIENT_QSCHEMA,
|
||||||
fun ?MODULE:qs2ms/2,
|
fun ?MODULE:qs2ms/2,
|
||||||
fun ?MODULE:format_channel_info/2
|
fun ?MODULE:format_channel_info/2,
|
||||||
|
Options
|
||||||
);
|
);
|
||||||
Node0 ->
|
Node0 ->
|
||||||
case emqx_utils:safe_to_existing_atom(Node0) of
|
case emqx_utils:safe_to_existing_atom(Node0) of
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Improve the speed of clients querying in HTTP API `/clients` endpoint with default parameters
|
Loading…
Reference in New Issue