From 1dceed32b81007b372d4854ee8b8178b59d79fe2 Mon Sep 17 00:00:00 2001 From: Cam Saul <1455846+camsaul@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:44:34 -0700 Subject: [PATCH] Make the App DB transaction isolation level READ_COMMITTED for MySQL [MEGA PERFORMANCE BOOST] (#44505) * Make the App DB transaction isolation level READ_COMMITTED for MySQL/MariaDB [MEGA PERFORMANCE BOOST] * Add test --- src/metabase/db/data_source.clj | 11 ++++++++--- test/metabase/db/connection_test.clj | 7 +++++++ test/metabase/db/data_source_test.clj | 10 +++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/src/metabase/db/data_source.clj b/src/metabase/db/data_source.clj index 622ad236cb9..6b781adf5cc 100644 --- a/src/metabase/db/data_source.clj +++ b/src/metabase/db/data_source.clj @@ -31,9 +31,14 @@ javax.sql.DataSource (getConnection [_] - (if properties - (DriverManager/getConnection url properties) - (DriverManager/getConnection url))) + (doto (if properties + (DriverManager/getConnection url properties) + (DriverManager/getConnection url)) + ;; MySQL/MariaDB default to REPEATABLE_READ which ends up making everything SLOW because it locks all the time. + ;; Postgres defaults to READ_COMMITTED. Explicitly set transaction isolation for new connections so we can make + ;; sure we're using READ_COMMITTED. See https://metaboat.slack.com/archives/C04DN5VRQM6/p1718912820432359 for more + ;; info. + (.setTransactionIsolation java.sql.Connection/TRANSACTION_READ_COMMITTED))) ;; we don't use (.getConnection this url user password) so we don't need to implement it. (getConnection [_ _user _password] diff --git a/test/metabase/db/connection_test.clj b/test/metabase/db/connection_test.clj index 19b7d45d18b..1e8ff8b7a58 100644 --- a/test/metabase/db/connection_test.clj +++ b/test/metabase/db/connection_test.clj @@ -1,6 +1,7 @@ (ns metabase.db.connection-test (:require [clojure.test :refer :all] + [metabase.db.connection :as mdb.connection] [metabase.test :as mt] [metabase.test.fixtures :as fixtures] [toucan2.core :as t2] @@ -131,3 +132,9 @@ (catch Exception e (when-not (is-transaction-exception? e) (throw e)))))))) + +(deftest ^:parallel transaction-isolation-level-test + (testing "We should always use READ_COMMITTED for the app DB (#44505)" + (with-open [conn (.getConnection mdb.connection/*application-db*)] + (is (= java.sql.Connection/TRANSACTION_READ_COMMITTED + (.getTransactionIsolation conn)))))) diff --git a/test/metabase/db/data_source_test.clj b/test/metabase/db/data_source_test.clj index 97209fd8b22..7a54dccb2ba 100644 --- a/test/metabase/db/data_source_test.clj +++ b/test/metabase/db/data_source_test.clj @@ -12,7 +12,7 @@ (defn- ->DataSource [s properties] (#'mdb.data-source/->DataSource s (some-> (not-empty properties) connection-pool/map->properties))) -(deftest broken-out-details-test +(deftest ^:parallel broken-out-details-test (testing :postgres (is (= (->DataSource "jdbc:postgresql://localhost:5432/metabase" @@ -51,7 +51,7 @@ (is (= [{:one 1}] (jdbc/query {:connection conn} "SELECT 1 AS one;"))))))) -(deftest connection-string-test +(deftest ^:parallel connection-string-test (let [data-source (mdb.data-source/raw-connection-string->DataSource (format "jdbc:h2:mem:%s" (mt/random-name)))] (with-open [conn (.getConnection data-source)] @@ -72,7 +72,7 @@ (is (= (mdb.data-source/raw-connection-string->DataSource "jdbc:postgresql://localhost:5432/metabase") (mdb.data-source/raw-connection-string->DataSource "postgres://localhost:5432/metabase"))))) -(deftest wonky-connection-string-test +(deftest ^:parallel wonky-connection-string-test (testing "Should handle malformed user:password@host:port strings (#14678, #20121)" (doseq [subprotocol ["postgresql" "mysql"]] (testing "user AND password" @@ -96,7 +96,7 @@ {"user" "cam"}) (mdb.data-source/raw-connection-string->DataSource (str subprotocol "://cam@localhost/metabase?password=1234"))))))))) -(deftest raw-connection-string-with-separate-username-and-password-test +(deftest ^:parallel raw-connection-string-with-separate-username-and-password-test (testing "Raw connection string should support separate username and/or password (#20122)" (testing "username and password" (is (= (->DataSource @@ -116,7 +116,7 @@ (mdb.data-source/raw-connection-string->DataSource "postgres://metabase" nil "1234") (mdb.data-source/raw-connection-string->DataSource "postgres://metabase" "" "1234")))))) -(deftest equality-test +(deftest ^:parallel equality-test (testing "Two DataSources with the same URL should be equal" (is (= (mdb.data-source/raw-connection-string->DataSource "ABCD") (mdb.data-source/raw-connection-string->DataSource "ABCD")))) -- GitLab