From: Federico Caselli Date: Thu, 30 Dec 2021 22:29:55 +0000 (+0100) Subject: Imrpove MySQL/MariaDB dialect initialization. X-Git-Tag: rel_2_0_0b1~562^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e06f0f579df45116696fed78d65abcccc1dc3e3;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Imrpove MySQL/MariaDB dialect initialization. Replace ``SHOW VARIABLES LIKE`` statement with equivalent ``SELECT @@variable`` in MySQL and MariaDB dialect initialization. This should avoid mutex contention caused by ``SHOW VARIABLES``, improving initialization performance. Change-Id: Id836ef534fcc1473c7aaf9270d08a4da9b8f62cf closes: #7518 --- diff --git a/doc/build/changelog/unreleased_14/7518.rst b/doc/build/changelog/unreleased_14/7518.rst new file mode 100644 index 0000000000..6264297cb1 --- /dev/null +++ b/doc/build/changelog/unreleased_14/7518.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: change, mysql + :tickets: 7518 + + Replace ``SHOW VARIABLES LIKE`` statement with equivalent + ``SELECT @@variable`` in MySQL and MariaDB dialect initialization. + This should avoid mutex contention caused by ``SHOW VARIABLES``, + improving initialization performance. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 5be0574954..f20b9b6931 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -3079,24 +3079,21 @@ class MySQLDialect(default.DefaultDialect): # https://dev.mysql.com/doc/refman/en/identifier-case-sensitivity.html charset = self._connection_charset - show_var = connection.execute( - sql.text("SHOW VARIABLES LIKE 'lower_case_table_names'") - ) - row = self._compat_first( - show_var, - charset=charset, + show_var = connection.exec_driver_sql( + "SELECT @@lower_case_table_names" ) + row = self._compat_first(show_var, charset=charset) if not row: cs = 0 else: # 4.0.15 returns OFF or ON according to [ticket:489] # 3.23 doesn't, 4.0.27 doesn't.. - if row[1] == "OFF": + if row[0] == "OFF": cs = 0 - elif row[1] == "ON": + elif row[0] == "ON": cs = 1 else: - cs = int(row[1]) + cs = int(row[0]) self._casing = cs return cs @@ -3115,7 +3112,7 @@ class MySQLDialect(default.DefaultDialect): def _detect_sql_mode(self, connection): row = self._compat_first( - connection.exec_driver_sql("SHOW VARIABLES LIKE 'sql_mode'"), + connection.exec_driver_sql("SELECT @@sql_mode"), charset=self._connection_charset, ) @@ -3126,7 +3123,7 @@ class MySQLDialect(default.DefaultDialect): ) self._sql_mode = "" else: - self._sql_mode = row[1] or "" + self._sql_mode = row[0] or "" def _detect_ansiquotes(self, connection): """Detect and adjust for the ANSI_QUOTES sql mode.""" diff --git a/lib/sqlalchemy/dialects/mysql/pyodbc.py b/lib/sqlalchemy/dialects/mysql/pyodbc.py index 69cc6487d1..9cae7b7145 100644 --- a/lib/sqlalchemy/dialects/mysql/pyodbc.py +++ b/lib/sqlalchemy/dialects/mysql/pyodbc.py @@ -43,11 +43,11 @@ Pass through exact pyodbc connection string:: """ # noqa import re -import sys from .base import MySQLDialect from .base import MySQLExecutionContext from .types import TIME +from ... import exc from ... import util from ...connectors.pyodbc import PyODBCConnector from ...sql.sqltypes import Time @@ -88,13 +88,14 @@ class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect): # # If it's decided that issuing that sort of SQL leaves you SOL, then # this can prefer the driver value. - rs = connection.exec_driver_sql( - "SHOW VARIABLES LIKE 'character_set%%'" - ) - opts = {row[0]: row[1] for row in self._compat_fetchall(rs)} - for key in ("character_set_connection", "character_set"): - if opts.get(key, None): - return opts[key] + try: + value = connection.exec_driver_sql( + "select @@character_set_client" + ).scalar() + if value: + return value + except exc.DBAPIError: + pass util.warn( "Could not detect the connection character set. " @@ -121,15 +122,9 @@ class MySQLDialect_pyodbc(PyODBCConnector, MySQLDialect): # https://github.com/mkleehammer/pyodbc/wiki/Unicode pyodbc_SQL_CHAR = 1 # pyodbc.SQL_CHAR pyodbc_SQL_WCHAR = -8 # pyodbc.SQL_WCHAR - if sys.version_info.major > 2: - conn.setdecoding(pyodbc_SQL_CHAR, encoding="utf-8") - conn.setdecoding(pyodbc_SQL_WCHAR, encoding="utf-8") - conn.setencoding(encoding="utf-8") - else: - conn.setdecoding(pyodbc_SQL_CHAR, encoding="utf-8") - conn.setdecoding(pyodbc_SQL_WCHAR, encoding="utf-8") - conn.setencoding(str, encoding="utf-8") - conn.setencoding(unicode, encoding="utf-8") # noqa: F821 + conn.setdecoding(pyodbc_SQL_CHAR, encoding="utf-8") + conn.setdecoding(pyodbc_SQL_WCHAR, encoding="utf-8") + conn.setencoding(encoding="utf-8") return on_connect diff --git a/test/dialect/mysql/test_dialect.py b/test/dialect/mysql/test_dialect.py index 9a0f2bc0df..a96ea8cb48 100644 --- a/test/dialect/mysql/test_dialect.py +++ b/test/dialect/mysql/test_dialect.py @@ -59,7 +59,7 @@ class BackendDialectTest( engine = engines.testing_engine() def my_execute(self, statement, *args, **kw): - if statement.startswith("SHOW VARIABLES"): + if statement.startswith("SELECT @@"): statement = "SELECT 1 FROM DUAL WHERE 1=0" return real_exec(self, statement, *args, **kw)