Skip to content

Commit aa59d77

Browse files
committed
Bug#25418534: JSON_EXTRACT USING WILDCARDS TAKES FOREVER
Patch #8: seek_no_dup_elimination() is only called on documents that are on binary format, but it accesses the document through the Json_wrapper interface. This patch makes it use the json_binary interface instead to avoid the unnecessary indirection via Json_wrapper. Microbenchmarks (64-bit, Intel Core i7-4770 3.4 GHz, GCC 6.3): BM_JsonBinarySearchEllipsis 20462 [+213.1%] BM_JsonBinarySearchEllipsis_OnlyOne 75 [ +18.7%] BM_JsonBinarySearchKey 67 [ +14.9%] Change-Id: Idb74afe8cbac53eb45dab62a677282df9465ae6b
1 parent f08d729 commit aa59d77

File tree

2 files changed

+49
-80
lines changed

2 files changed

+49
-80
lines changed

sql/json_binary.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,12 @@ class Value
249249
return *this;
250250
}
251251

252+
/** Is this value an array? */
253+
bool is_array() const { return m_type == ARRAY; }
254+
255+
/** Is this value an object? */
256+
bool is_object() const { return m_type == OBJECT; }
257+
252258
private:
253259
/*
254260
Instances use only one of m_data, m_int_value and m_double_value,

sql/json_dom.cc

Lines changed: 43 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2152,7 +2152,7 @@ bool Json_dom::seek(const Json_seekable_path &path,
21522152
auto-wrapping. Those paths can take advantage of the efficient
21532153
positioning logic of json_binary::Value.
21542154
2155-
@param[in] wrapper the wrapper to search
2155+
@param[in] value the JSON value to search
21562156
@param[in] current_leg iterator to the first path leg to look at.
21572157
Usually called on the root document with an iterator pointing to
21582158
the beginning of the path, and then incremented in recursive calls
@@ -2165,143 +2165,106 @@ bool Json_dom::seek(const Json_seekable_path &path,
21652165
21662166
@returns false if there was no error, otherwise true on error
21672167
*/
2168-
static bool seek_no_dup_elimination(const Json_wrapper &wrapper,
2168+
static bool seek_no_dup_elimination(const json_binary::Value &value,
21692169
const Json_path_iterator &current_leg,
21702170
const Json_path_iterator &last_leg,
21712171
Json_wrapper_vector *hits,
21722172
bool auto_wrap,
21732173
bool only_need_one)
21742174
{
2175-
// DOMs are searched using Json_dom::seek() instead.
2176-
DBUG_ASSERT(!wrapper.is_dom());
2177-
21782175
if (current_leg == last_leg)
2179-
return hits->push_back(wrapper);
2176+
return hits->emplace_back(value);
21802177

21812178
const Json_path_leg *path_leg= *current_leg;
21822179
const Json_path_iterator next_leg= current_leg + 1;
2183-
const enum_json_type jtype= wrapper.type();
21842180

21852181
switch (path_leg->get_type())
21862182
{
21872183
case jpl_member:
21882184
{
2189-
switch (jtype)
2190-
{
2191-
case enum_json_type::J_OBJECT:
2192-
{
2193-
Json_wrapper member= wrapper.lookup(path_leg->get_member_name());
2194-
2195-
if (member.type() != enum_json_type::J_ERROR)
2196-
{
2197-
// recursion
2198-
if (seek_no_dup_elimination(member, next_leg, last_leg, hits,
2199-
auto_wrap, only_need_one))
2200-
return true; /* purecov: inspected */
2201-
}
2202-
return false;
2203-
}
2185+
if (!value.is_object())
2186+
return false;
22042187

2205-
default:
2206-
{
2207-
return false;
2208-
}
2209-
} // end inner switch on wrapper type
2188+
json_binary::Value member= value.lookup(path_leg->get_member_name());
2189+
if (member.type() == json_binary::Value::ERROR)
2190+
return false;
2191+
2192+
// recursion
2193+
return seek_no_dup_elimination(member, next_leg, last_leg, hits,
2194+
auto_wrap, only_need_one);
22102195
}
22112196

22122197
case jpl_member_wildcard:
2198+
if (!value.is_object())
2199+
return false;
2200+
2201+
for (size_t i= 0, size= value.element_count(); i < size; ++i)
22132202
{
2214-
switch (jtype)
2215-
{
2216-
case enum_json_type::J_OBJECT:
2217-
{
2218-
for (Json_wrapper_object_iterator iter= wrapper.object_iterator();
2219-
!iter.empty(); iter.next())
2220-
{
2221-
if (is_seek_done(hits, only_need_one))
2222-
return false;
2223-
2224-
// recursion
2225-
if (seek_no_dup_elimination(iter.elt().second, next_leg, last_leg,
2226-
hits, auto_wrap, only_need_one))
2227-
return true; /* purecov: inspected */
2228-
}
2229-
return false;
2230-
}
2203+
if (is_seek_done(hits, only_need_one))
2204+
return false;
22312205

2232-
default:
2233-
{
2234-
return false;
2235-
}
2236-
} // end inner switch on wrapper type
2206+
// recursion
2207+
if (seek_no_dup_elimination(value.element(i), next_leg, last_leg,
2208+
hits, auto_wrap, only_need_one))
2209+
return true; /* purecov: inspected */
22372210
}
22382211

2212+
return false;
2213+
22392214
case jpl_array_cell:
2240-
if (jtype == enum_json_type::J_ARRAY)
2215+
if (value.is_array())
22412216
{
2242-
const Json_array_index idx= path_leg->first_array_index(wrapper.length());
2217+
const Json_array_index idx=
2218+
path_leg->first_array_index(value.element_count());
22432219
return idx.within_bounds() &&
2244-
seek_no_dup_elimination(wrapper[idx.position()], next_leg, last_leg, hits,
2245-
auto_wrap, only_need_one);
2220+
seek_no_dup_elimination(value.element(idx.position()), next_leg,
2221+
last_leg, hits, auto_wrap, only_need_one);
22462222
}
22472223
return auto_wrap && path_leg->is_autowrap() &&
2248-
seek_no_dup_elimination(wrapper, next_leg, last_leg, hits,
2224+
seek_no_dup_elimination(value, next_leg, last_leg, hits,
22492225
auto_wrap, only_need_one);
22502226

22512227
case jpl_array_range:
22522228
case jpl_array_cell_wildcard:
2253-
if (jtype == enum_json_type::J_ARRAY)
2229+
if (value.is_array())
22542230
{
2255-
const auto range= path_leg->get_array_range(wrapper.length());
2256-
for (size_t idx= range.m_begin; idx < range.m_end; idx++)
2231+
const auto range= path_leg->get_array_range(value.element_count());
2232+
for (size_t i= range.m_begin; i < range.m_end; ++i)
22572233
{
22582234
if (is_seek_done(hits, only_need_one))
22592235
return false;
22602236

22612237
// recursion
2262-
if (seek_no_dup_elimination(wrapper[idx], next_leg, last_leg, hits,
2238+
if (seek_no_dup_elimination(value.element(i), next_leg, last_leg, hits,
22632239
auto_wrap, only_need_one))
22642240
return true; /* purecov: inspected */
22652241
}
22662242
return false;
22672243
}
22682244
return auto_wrap && path_leg->is_autowrap() &&
2269-
seek_no_dup_elimination(wrapper, next_leg, last_leg, hits,
2245+
seek_no_dup_elimination(value, next_leg, last_leg, hits,
22702246
auto_wrap, only_need_one);
22712247

22722248
case jpl_ellipsis:
22732249
// recursion
2274-
if (seek_no_dup_elimination(wrapper, next_leg, last_leg, hits,
2250+
if (seek_no_dup_elimination(value, next_leg, last_leg, hits,
22752251
auto_wrap, only_need_one))
22762252
return true; /* purecov: inspected */
2277-
if (jtype == enum_json_type::J_ARRAY)
2278-
{
2279-
const size_t length= wrapper.length();
2280-
for (size_t idx= 0; idx < length; ++idx)
2281-
{
2282-
if (is_seek_done(hits, only_need_one))
2283-
return false;
22842253

2285-
// recursion
2286-
if (seek_no_dup_elimination(wrapper[idx], current_leg, last_leg, hits,
2287-
auto_wrap, only_need_one))
2288-
return true; /* purecov: inspected */
2289-
}
2290-
}
2291-
else if (jtype == enum_json_type::J_OBJECT)
2254+
if (value.is_array() || value.is_object())
22922255
{
2293-
for (Json_wrapper_object_iterator iter= wrapper.object_iterator();
2294-
!iter.empty(); iter.next())
2256+
for (size_t i= 0, size= value.element_count(); i < size; ++i)
22952257
{
22962258
if (is_seek_done(hits, only_need_one))
22972259
return false;
22982260

22992261
// recursion
2300-
if (seek_no_dup_elimination(iter.elt().second, current_leg, last_leg,
2262+
if (seek_no_dup_elimination(value.element(i), current_leg, last_leg,
23012263
hits, auto_wrap, only_need_one))
23022264
return true; /* purecov: inspected */
23032265
}
23042266
}
2267+
23052268
return false;
23062269
} // end outer switch on leg type
23072270

@@ -2343,7 +2306,7 @@ bool Json_wrapper::seek(const Json_seekable_path &path,
23432306
return false;
23442307
}
23452308

2346-
return seek_no_dup_elimination(*this, path.begin(), path.end(), hits,
2309+
return seek_no_dup_elimination(m_value, path.begin(), path.end(), hits,
23472310
auto_wrap, only_need_one);
23482311
}
23492312

@@ -3719,7 +3682,7 @@ bool Json_wrapper::attempt_binary_update(const Field_json *field,
37193682

37203683
// Find the parent of the value we want to modify.
37213684
Json_wrapper_vector hits(key_memory_JSON);
3722-
if (seek_no_dup_elimination(*this, path.begin(), path.end() - 1, &hits,
3685+
if (seek_no_dup_elimination(m_value, path.begin(), path.end() - 1, &hits,
37233686
false, true))
37243687
return true; /* purecov: inspected */
37253688

@@ -3865,7 +3828,7 @@ bool Json_wrapper::binary_remove(const Field_json *field,
38653828
*found_path= false;
38663829

38673830
Json_wrapper_vector hits(key_memory_JSON);
3868-
if (seek_no_dup_elimination(*this, path.begin(), path.end() - 1, &hits,
3831+
if (seek_no_dup_elimination(m_value, path.begin(), path.end() - 1, &hits,
38693832
false, true))
38703833
return true; /* purecov: inspected */
38713834

0 commit comments

Comments
 (0)