Bug #107745 | ODBC Massive Performance Hit (Regression starting in 8.0.27) | ||
---|---|---|---|
Submitted: | 5 Jul 2022 3:30 | Modified: | 13 Feb 2023 21:24 |
Reporter: | Joseph DeSantis last | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | Connector / ODBC | Severity: | S2 (Serious) |
Version: | 8.0.27 through latest, 8.0.32 | OS: | Any |
Assigned to: | CPU Architecture: | Any |
[5 Jul 2022 3:30]
Joseph DeSantis last
[5 Jul 2022 7:18]
MySQL Verification Team
Hello Joseph, Thank you for the report and feedback. regards, Umesh
[5 Jul 2022 13:18]
Bogdan Degtyariov
Hi Joseph, The bottle neck in this case is the C locale enforcement, which we had to add for compatibility reasons in 8.0.27. Unfortunately, the process of setting the locale and restoring it back is consuming CPU time. Therefore, executing a large number of queries with parameters one after another had such negative performance impact. This option can be disabled by adding NO_LOCALE=1 to the connection string. I run your python code and here are the results: -------------------------------------------- ODBC Driver 8.0.29 (locale is not disabled): OS: Windows 10 Python: 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] PyODBC Driver: 4.0.32 Elapsed Time: 13.221230900031514 -------------------------------------------- ODBC Driver 8.0.29 (locale is disabled by using NO_LOCALE=1): OS: Windows 10 Python: 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] PyODBC Driver: 4.0.32 Elapsed Time: 8.015281299944036 -------------------------------------------- ODBC Driver 8.0.26 OS: Windows 10 Python: 3.10.4 (tags/v3.10.4:9d38120, Mar 23 2022, 23:13:41) [MSC v.1929 64 bit (AMD64)] PyODBC Driver: 4.0.32 Elapsed Time: 8.08586250001099 As you can see the version 8.0.29 with NO_LOCALE=1 even performed slightly faster than 8.0.26. This is just a workaround, not a permanent solution. The driver should be able to manage locales more efficiently.
[5 Jul 2022 15:59]
Joseph DeSantis last
Bogdan Degtyariov, I appreciate you taking a look into this with me. I am unfortunately not seeing the same results using NO_LOCALE=1 As you suggested I have changed my connection string in my example code above to the following: DRIVER=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so;SERVER=db;DATABASE=sys;UID=root;PWD=example;charset=utf8mb4;NO_LOCALE=1 I have also tried with a semicolon at the end: DRIVER=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc8w.so;SERVER=db;DATABASE=sys;UID=root;PWD=example;charset=utf8mb4;NO_LOCALE=1; There seems to be no change in performance using NO_LOCAL vs not using it for me on the latest 8.0.29.
[27 Jul 2022 11:31]
Bogdan Degtyariov
Posted by developer: The patch is pushed into release/8.0.31 branch of the source tree.
[10 Aug 2022 18:30]
Philip Olson
Posted by developer: Fixed as of the upcoming MySQL Connector/ODBC 8.0.31 release, and here's the proposed changelog entry from the documentation team: Improved query parameter support and performance with prepared statements. Thank you for the bug report.
[20 Oct 2022 6:05]
Joseph DeSantis last
@Philip Olson @Bogdan Degtyariov Can you please re-open this bug report. The ODBC driver 8.0.31 did not fix this problem. Using the above testing method run the following: docker-compose down && docker-compose build --build-arg odbcdlurl=https://dev.mysql.com/get/Downloads/Connector-ODBC/8.0/mysql-connector-odbc-8.0.31-linux-g... && docker-compose up Here are the performance metrics: 8.0.19 timings: ~ 15 seconds 8.0.31 timings: ~26 seconds As such the same performance problems are still persisting in the latest release of the ODBC driver.
[20 Oct 2022 7:47]
Bogdan Degtyariov
Hi Joseph, We used our performance tests that found huge performance impact upon the call to setlocale() function. This was eliminated and out tests showed significant improvements. Same was observed with the python script provided in the bug description. It was not done in docker environment though... We are reopening the bug since it did not improve the situation for you. More testing and profiling needs to be done in order to determine the bottleneck.
[25 Jan 2023 2:25]
Bogdan Degtyariov
Posted by developer: The docker testing is producing inconsistent results when 8.0.32 is often outperforming 8.0.19: 8.0.19: test_1 | Elapsed Time: 7.136530666000908 test_1 | Elapsed Time: 9.754535002997727 test_1 | Elapsed Time: 8.129148177002207 8.0.29: test_1 | Elapsed Time: 10.258983902000182 test_1 | Elapsed Time: 9.512771303998306 test_1 | Elapsed Time: 8.810006886997144 8.0.32: test_1 | Elapsed Time: 7.966252436002833 test_1 | Elapsed Time: 8.201184498000657 test_1 | Elapsed Time: 8.034129674000724 However, the general server log for 8.0.29 and 8.0.32 contains "Reset stmt" after each stmt execution whilst 8.0.19 doesn't. This might have an impact on the execution time.
[27 Jan 2023 2:07]
Joseph DeSantis last
Yes, I do believe the "Reset stmt" could be to blame here. In order to address the inconsistent results on your local machine, I have created a GitHub Repository with an associated GitHub Actions CI process to automate this Performance testing. I have simply taken the tests provided in my original bug report, automated the running of them via GitHub actions, and then finally reported back the results of the tests in the form of a GitHub comment. I have included over 10 test runs, all of which still confirm the Massive Performance degradation. https://github.com/ILoveMySQL/MySQL-Connector-ODBC-Performance-Testing/pull/1
[27 Jan 2023 2:16]
Joseph DeSantis last
The following URL is a link to more test runs which also confirm the Performance issue is still in the latest version of the ODBC Connector. https://github.com/ILoveMySQL/MySQL-Connector-ODBC-Performance-Testing/pull/2 In short, there is no indication that this performance issue has gotten better. Most of our production processes are still running on 2 year + old ODBC versions until we can get this resolved. I also have updated the impacted versions to include `8.0.32`.
[8 Feb 2023 3:01]
Bogdan Degtyariov
Posted by developer: Two performance issues were identified and fixed in the scope of this patch: 1. The frequent use setlocale() function to enforce the use of '.' character as the decimal separator in SQLFetch() SQLGetData() causing multiple locale switches upon each fetch of the row and getting data for each column in a row, which in some cases resulted in slow-downs up to 60 times. Now setlocale() is only called once on the driver initialization stage, which should not have impact on the ODBC driver performance in all further calls. 2. The use of locale-dependent function std::strtod() was replaced by a custom implementation of the float/double conversion used internally in MySQL Server, which is at least twice faster as std::strtod().
[13 Feb 2023 21:24]
Philip Olson
Posted by developer: Fixed as of the upcoming MySQL Connector/ODBC 8.0.33 release, and here's the proposed changelog entry from the documentation team: Improved prepared statement performance by decreasing the frequency of setlocale() calls used to enforce the '.' character as a decimal separator. Thank you for the bug report, and thank you for the extensive testing and re-testing.