Uploaded image for project: 'Moodle'
  1. Moodle
  2. MDL-78030

Make tablelib and reports faster by combining count query into main query

XMLWordPrintable

    • MOODLE_405_STABLE
    • MDL-78030-main-improvement
    • Hide

      Setup requirements

      To ease the test, please use Moodle-docker. The improvement will be tested with PostgreSQL, MariaDB, Oracle and MySQL.

      Why testing MySQL?

      When there is a list with pagination using the get_counted_records_sql() or get_counted_recordset_sql(), then it will generate a new SQL query whether the database "supports" the count window functions, and we want to make sure that the query is executed without any errors and present the same data across the supported database engines.

      MySQL and MSSQL didn't support the count window function due to its performance, but we still need to test them to ensure the data are present correctly and the is_count_window_function_supported() function works properly.

      Unit Testing

      Run the below command:

      vendor/bin/phpunit --filter="test_count_window_function"

      Manual Testing 1: Course participants

      1. Login as an administrator.
      2. Go to Site Administration > Development > Make Test Course.
      3. Choose "M" from the Size of Course drop-down menu.
      4. Specify the coursename with "Test Course M".
      5. Click on the Create Course button.
      6. Navigate to the course page.
      7. Click the Participants
      8. Verify that the participant list is identical to the list without the patch.
        • It's ok if they are ordered differently.
      9. Verify that the ordering column has the same result as without the patch.
      10. Verify that the pagination is working without any errors and the result is the same as without the patch

      Manual Testing 2: Language customisation

      1. Login as an administrator
      2. Go to Site Administration > General > Language Customisation
      3. Select "English (en)" in the dropdown
      4. Click the "Open language pack for editing" button
      5. Wait until the progress is complete.
      6. Click the "Continue" button
      7. Select "moodle.php" in the "Show strings of these components"
      8. Click the "Show strings" button
      9. Verify that the list is identical to the list without the patch.
      10. Verify that all the filters work correctly and the list is identical to the list without the patch.
      11. Verify that the pagination is working without any errors and the list is identical to the list without the patch.

      Note:
      Please repeat all the tests with different database engines (PostgreSQL, MariaDB, Oracle and MySQL).

      CLI for Benchmarking

      1. Do not apply the patch
      2. Copy the scripts benchmark.php to the admin/cli directory.
      3. Running the below commands:

        bin/moodle-docker-compose exec webserver php admin/cli/benchmark.php -u=10000 -t=10 

      4. After completing the process, note the Average time (Avg Time).
      5. Please repeat all the steps above with different database engines (PostgreSQL, MariaDB, Oracle).
      6. Apply the patch
      7. Running the below commands:

        bin/moodle-docker-compose exec webserver php admin/cli/benchmark.php -u=10000 -t=10 

      8. After completing the process, note the Average time (Avg Time).
      9. Please repeat all the steps above with different database engines (PostgreSQL, MariaDB, Oracle).
      10. Compare the AVG time before and after the patch between the database engines.
      11. VERIFY that the result with the patch has a lower average than without the patch.
         
      Show
      Setup requirements To ease the test, please use Moodle-docker . The improvement will be tested with PostgreSQL, MariaDB, Oracle and MySQL. Why testing MySQL? When there is a list with pagination using the get_counted_records_sql() or get_counted_recordset_sql(), then it will generate a new SQL query whether the database "supports" the count window functions, and we want to make sure that the query is executed without any errors and present the same data across the supported database engines. MySQL and MSSQL didn't support the count window function due to its performance, but we still need to test them to ensure the data are present correctly and the is_count_window_function_supported() function works properly. Unit Testing Run the below command: vendor/bin/phpunit --filter= "test_count_window_function" Manual Testing 1: Course participants Login as an administrator. Go to Site Administration > Development > Make Test Course. Choose "M" from the Size of Course drop-down menu. Specify the coursename with "Test Course M". Click on the Create Course button. Navigate to the course page. Click the Participants Verify that the participant list is identical to the list without the patch. It's ok if they are ordered differently. Verify that the ordering column has the same result as without the patch. Verify that the pagination is working without any errors and the result is the same as without the patch Manual Testing 2: Language customisation Login as an administrator Go to Site Administration > General > Language Customisation Select "English (en)" in the dropdown Click the "Open language pack for editing" button Wait until the progress is complete. Click the "Continue" button Select "moodle.php" in the "Show strings of these components" Click the "Show strings" button Verify that the list is identical to the list without the patch. Verify that all the filters work correctly and the list is identical to the list without the patch. Verify that the pagination is working without any errors and the list is identical to the list without the patch. Note: Please repeat all the tests with different database engines (PostgreSQL, MariaDB, Oracle and MySQL). CLI for Benchmarking Do not apply the patch Copy the scripts benchmark.php to the admin/cli directory. Running the below commands: bin/moodle-docker-compose exec webserver php admin/cli/benchmark.php -u= 10000 -t= 10 After completing the process, note the Average time (Avg Time). Please repeat all the steps above with different database engines (PostgreSQL, MariaDB, Oracle). Apply the patch Running the below commands: bin/moodle-docker-compose exec webserver php admin/cli/benchmark.php -u= 10000 -t= 10 After completing the process, note the Average time (Avg Time). Please repeat all the steps above with different database engines (PostgreSQL, MariaDB, Oracle). Compare the AVG time before and after the patch between the database engines. VERIFY that the result with the patch has a lower average than without the patch.  
    • 6
    • Team Hedgehog 2023 Sprint 4.3, Team Hedgehog 2023 Review 4, Team Hedgehog 2024 Sprint 1.1, Team Hedgehog 2024 Sprint 1.2, Team Hedgehog 2024 Sprint 1.3, Team Hedgehog 2024 Sprint 1.4, Team Hedgehog 2024 Review 1, Team Hedgehog 2024 Sprint 2.1, Team Hedgehog 2024 Sprint 2.2, Team Hedgehog 2024 Sprint 2.3, Team Hedgehog 2024 Review 2

      If you have any sufficiently large data set the query behind anything in tablelib and several places where reports are used, operations will get slower. When viewing the report it grabs a page of data, and it also grabs the total count of records without the pagination. Both of these raw queries take effectively the same amount of time to run which doubles the report time and db load.

      Using window functions both of these can be combined into a single query for an easy 2x performance win across the board in all reports with no changes to any of the reports which is a pretty rare win

      So for a query like this:

         SELECT username
           FROM {user}
          WHERE username LIKE '%gmail%'

      we can auto wrap it like this:

      SELECT results.*, COUNT(*) OVER() AS full_count FROM (
         SELECT username
           FROM {user}
          WHERE username LIKE '%gmail%'
      ) results

      This takes no appreciable difference from the original query.

      A more detailed example with some edge cases to cover is here:

      https://makandracards.com/makandra/513145-postgresql-paginate-and-count-in-one-query-using-window-functions

      Window function support should be fairly good across all supported DB's and we can fall back to existing count where it isn't.

        1. (1) 1 Passed -- (Main)MDL-78030.png
          (1) 1 Passed -- (Main)MDL-78030.png
          47 kB
        2. (2) 10 Passed -- (Main)MDL-78030.png
          (2) 10 Passed -- (Main)MDL-78030.png
          171 kB
        3. (2) 8 Passed -- (Main)MDL-78030.png
          (2) 8 Passed -- (Main)MDL-78030.png
          282 kB
        4. (2) 9 Passed -- (Main)MDL-78030.png
          (2) 9 Passed -- (Main)MDL-78030.png
          466 kB
        5. (3) 10 Passed -- (Main)MDL-78030.png
          (3) 10 Passed -- (Main)MDL-78030.png
          131 kB
        6. (3) 11 Passed -- (Main)MDL-78030.png
          (3) 11 Passed -- (Main)MDL-78030.png
          125 kB
        7. (3) 9 Passed -- (Main)MDL-78030.png
          (3) 9 Passed -- (Main)MDL-78030.png
          108 kB
        8. benchmark_sql.php
          8 kB
        9. benchmark.php
          6 kB
        10. global_search_time_executed_77830.txt
          1 kB
        11. mdl78030_benchmark_existing.png
          mdl78030_benchmark_existing.png
          100 kB
        12. mdl78030_benchmark_improvement.png
          mdl78030_benchmark_improvement.png
          101 kB
        13. mdl78030_benchmark_sql.png
          mdl78030_benchmark_sql.png
          126 kB
        14. mdl78030_exec_time.png
          mdl78030_exec_time.png
          49 kB
        15. MDL-78030_namedparam.png
          MDL-78030_namedparam.png
          36 kB
        16. MDL-78030_oracle1.png
          MDL-78030_oracle1.png
          180 kB
        17. MDL-78030_oracle2.png
          MDL-78030_oracle2.png
          177 kB
        18. MDL-78030_oracle3.png
          MDL-78030_oracle3.png
          186 kB
        19. MDL-78030_oracle4.png
          MDL-78030_oracle4.png
          69 kB
        20. MDL-78030_oracle5.png
          MDL-78030_oracle5.png
          61 kB
        21. MDL-78030_oracle6.png
          MDL-78030_oracle6.png
          47 kB
        22. MDL-78030- 1.png
          MDL-78030- 1.png
          238 kB
        23. MDL-78030 - 2.png
          MDL-78030 - 2.png
          195 kB
        24. MDL-78030 - 3.png
          MDL-78030 - 3.png
          377 kB
        25. MDL-78030 benchmark without.png
          MDL-78030 benchmark without.png
          131 kB
        26. MDL-78030 benchmark with patch.png
          MDL-78030 benchmark with patch.png
          130 kB
        27. MDL-78030 manual 1 - with and without patch.png
          MDL-78030 manual 1 - with and without patch.png
          540 kB
        28. MDL-78030 manual 1 without patch.png
          MDL-78030 manual 1 without patch.png
          352 kB
        29. MDL-78030 manual 1 with patch.png
          MDL-78030 manual 1 with patch.png
          352 kB
        30. MDL-78030 mariadb benchmark.png
          MDL-78030 mariadb benchmark.png
          200 kB
        31. MDL-78030 mariadb manual 2.png
          MDL-78030 mariadb manual 2.png
          181 kB
        32. MDL-78030 mariadb manual with and without patch.png
          MDL-78030 mariadb manual with and without patch.png
          563 kB
        33. MDL-78030 mariadb unit test.png
          MDL-78030 mariadb unit test.png
          36 kB
        34. MDL-78030 MySQL 1.png
          MDL-78030 MySQL 1.png
          37 kB
        35. MDL-78030 oracle benchmark before after.png
          MDL-78030 oracle benchmark before after.png
          201 kB
        36. MDL-78030 oracle manual testing 2 with and without patch.png
          MDL-78030 oracle manual testing 2 with and without patch.png
          107 kB
        37. MDL-78030 oracle unit test.png
          MDL-78030 oracle unit test.png
          36 kB
        38. participants_time_executed_77830.txt
          3 kB
        39. sorting_oracle.png
          sorting_oracle.png
          652 kB

            meirza.arson@moodle.com Meirza
            brendanheywood Brendan Heywood
            David Woloszyn David Woloszyn
            Shamim Rezaie Shamim Rezaie
            Simey Lameze Simey Lameze
            Votes:
            4 Vote for this issue
            Watchers:
            27 Start watching this issue

              Created:
              Updated:
              Resolved:

                Estimated:
                Original Estimate - 0 minutes
                0m
                Remaining:
                Remaining Estimate - 0 minutes
                0m
                Logged:
                Time Spent - 2 weeks, 1 day, 6 hours, 17 minutes
                2w 1d 6h 17m

                  Error rendering 'clockify-timesheets-time-tracking-reports:timer-sidebar'. Please contact your Jira administrators.