-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimise autocomplete query #38080
Optimise autocomplete query #38080
Changes from 8 commits
65daf4c
dc83b6b
ac0e2b5
732c888
6e28535
13c31ce
fde4b11
fdbfe60
ddcba4e
6512c94
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -551,10 +551,11 @@ | |
:%lower.metabase_field/name [:like (u/lower-case-en search-string)] | ||
:metabase_field.visibility_type [:not-in ["sensitive" "retired"]] | ||
:table.db_id db-id | ||
{:order-by [[[:lower :metabase_field.name] :asc] | ||
[[:lower :table.name] :asc]] | ||
:left-join [[:metabase_table :table] [:= :table.id :metabase_field.table_id]] | ||
:limit limit})) | ||
{:order-by [[[:lower :metabase_field.name] :asc] | ||
[[:lower :table.name] :asc]] | ||
:inner-join [[:metabase_table :table] [:and :table.active | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be worth commenting that it was (counter-intuitively) faster to have the "active" check within the join, in case someone comes to optimize again. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hah, it felt intuitive for me - you get less data to join this way 😁 But sure, I can leave a comment there. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably you're right, my intuition is quite rusty and I didn't give much thought to it 😆 |
||
[:= :table.id :metabase_field.table_id]]] | ||
:limit limit})) | ||
|
||
(defn- autocomplete-results [tables fields limit] | ||
(let [tbl-count (count tables) | ||
|
@@ -620,11 +621,16 @@ | |
(when (and (str/blank? prefix) (str/blank? substring)) | ||
(throw (ex-info (tru "Must include prefix or search") {:status-code 400}))) | ||
(try | ||
(cond | ||
substring | ||
(autocomplete-suggestions id (str "%" substring "%")) | ||
prefix | ||
(autocomplete-suggestions id (str prefix "%"))) | ||
{:status 200 | ||
;; Presumably user will repeat same prefixes many times writing the query, | ||
;; so let them cache response to make autocomplete feel fast. 60 seconds | ||
;; is not enough to be a nuisance when schema or permissions change. Cache | ||
;; is user-specific since we're checking for permissions. | ||
:headers {"Cache-Control" "public, max-age=60" | ||
"Vary" "Cookie"} | ||
:body (cond | ||
substring (autocomplete-suggestions id (str "%" substring "%")) | ||
prefix (autocomplete-suggestions id (str prefix "%")))} | ||
Comment on lines
+629
to
+638
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: I'm a sucker for small methods and avoiding mixing too many levels of abstraction. I'd break out a small There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IDK, I'd rather this be "in the face" until a general pattern emerges... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rule of 3? Fine 😄 |
||
(catch Throwable e | ||
(log/warn e (trs "Error with autocomplete: {0}" (ex-message e)))))) | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be worth commenting that an index on
lower(name)
dramatically speeds the query up in DBs that support it, but we left it for now since Maria and H2 do not support indexes on computed fields. Perhaps they'll catch up in future? I also wonder if there are other use cases for a lowercase username, we could always materialize this as another column.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's actually not a filter problem, but an ordering one (weirdly). On stats adding a ngram index sped up query for 80 to 20 ms, but adding a index (which is used for sorting) speeds it up to 10 ms (no difference if with or without ngram index). 🤯