From 8eb25e5b14d6c70ca39229948a5a85596e142324 Mon Sep 17 00:00:00 2001 From: Oleksandr Yakushev <alex@bytopia.org> Date: Thu, 5 Sep 2024 20:25:48 +0300 Subject: [PATCH] perf: Miscellaneous card rendering improvements (#47679) * perf: Optimize reading rows into vectors in JDBC driver * perf: Use direct interop when computing with-time-zone-same-instant --- src/metabase/driver/sql_jdbc/execute.clj | 7 ++++--- src/metabase/util/date_2.clj | 12 +++++------- src/metabase/util/performance.clj | 11 +++++++++++ 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/metabase/driver/sql_jdbc/execute.clj b/src/metabase/driver/sql_jdbc/execute.clj index 3dfd8cf0ce4..0d69910de62 100644 --- a/src/metabase/driver/sql_jdbc/execute.clj +++ b/src/metabase/driver/sql_jdbc/execute.clj @@ -30,6 +30,7 @@ [metabase.util.i18n :refer [tru]] [metabase.util.log :as log] [metabase.util.malli :as mu] + [metabase.util.performance :as perf] [potemkin :as p]) (:import (java.sql Connection JDBCType PreparedStatement ResultSet ResultSetMetaData SQLFeatureNotSupportedException @@ -634,11 +635,11 @@ "Returns a thunk that can be called repeatedly to get the next row in the result set, using appropriate methods to fetch each value in the row. Returns `nil` when the result set has no more rows." [driver ^ResultSet rs ^ResultSetMetaData rsmeta] - (let [fns (for [i (column-range rsmeta)] - (read-column-thunk driver rs rsmeta (long i)))] + (let [fns (mapv #(read-column-thunk driver rs rsmeta (long %)) + (column-range rsmeta))] (log-readers driver rsmeta fns) (let [thunk (if (seq fns) - (apply juxt fns) + (perf/juxt* fns) (constantly []))] (fn row-thunk* [] (when (.next rs) diff --git a/src/metabase/util/date_2.clj b/src/metabase/util/date_2.clj index ab5c4ea6ece..e6a341e33d1 100644 --- a/src/metabase/util/date_2.clj +++ b/src/metabase/util/date_2.clj @@ -514,6 +514,8 @@ converts it to the corresponding offset/zoned type; for offset/zoned types, this applies an appropriate timezone shift.")) +(def ^:private local-time-0 (t/local-time 0)) + (extend-protocol WithTimeZoneSameInstant ;; convert to a OffsetTime with no offset (UTC); the OffsetTime method impl will apply the zone shift. LocalTime @@ -526,15 +528,11 @@ LocalDate (with-time-zone-same-instant [t zone-id] - (t/offset-date-time t (t/local-time 0) zone-id)) - - LocalDate - (with-time-zone-same-instant [t zone-id] - (t/offset-date-time t (t/local-time 0) zone-id)) + (with-time-zone-same-instant (LocalDateTime/of t local-time-0) zone-id)) LocalDateTime - (with-time-zone-same-instant [t zone-id] - (t/offset-date-time t zone-id)) + (with-time-zone-same-instant [t ^java.time.ZoneId zone-id] + (OffsetDateTime/of t (.getOffset (.getRules zone-id) t))) ;; instants are always normalized to UTC, so don't make any changes here. If you want to format in a different zone, ;; convert to an OffsetDateTime or ZonedDateTime first. diff --git a/src/metabase/util/performance.clj b/src/metabase/util/performance.clj index 58786746ac1..3deb78bef9d 100644 --- a/src/metabase/util/performance.clj +++ b/src/metabase/util/performance.clj @@ -69,3 +69,14 @@ (persistent! (reduce #(conj! %1 (f %2 %3 %4)) (transient []) coll1 coll2 coll3))) ([f coll1 coll2 coll3 coll4] (persistent! (reduce #(conj! %1 (f %2 %3 %4 %5)) (transient []) coll1 coll2 coll3 coll4)))) + +(defn juxt* + "Like `clojure.core/juxt`, but accepts a list of functions instead of varargs. Uses more efficient mapping." + [fns] + (let [fns (vec fns)] + (fn + ([] (mapv #(%) fns)) + ([x] (mapv #(% x) fns)) + ([x y] (mapv #(% x y) fns)) + ([x y z] (mapv #(% x y z) fns)) + ([x y z & args] (mapv #(apply % x y z args) fns))))) -- GitLab