{"id":18455187,"url":"https://github.com/timothyvanderaerden/ecto_mysql_extras","last_synced_at":"2025-08-28T23:49:26.169Z","repository":{"id":37584773,"uuid":"414178791","full_name":"timothyvanderaerden/ecto_mysql_extras","owner":"timothyvanderaerden","description":"Ecto MySQL (and MariaDB) database performance insights.","archived":false,"fork":false,"pushed_at":"2025-07-01T12:20:41.000Z","size":396,"stargazers_count":7,"open_issues_count":3,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-30T13:45:31.665Z","etag":null,"topics":["database","ecto","elixir","mariadb","mysql"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timothyvanderaerden.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-10-06T11:10:13.000Z","updated_at":"2025-05-25T13:47:46.000Z","dependencies_parsed_at":"2023-02-14T07:00:48.137Z","dependency_job_id":"adadebf1-087a-4aa5-af26-73e9c381d13a","html_url":"https://github.com/timothyvanderaerden/ecto_mysql_extras","commit_stats":{"total_commits":158,"total_committers":4,"mean_commits":39.5,"dds":"0.45569620253164556","last_synced_commit":"4c15ce90cf70d8cc5aa876f9a708d21a24f60867"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/timothyvanderaerden/ecto_mysql_extras","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timothyvanderaerden%2Fecto_mysql_extras","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timothyvanderaerden%2Fecto_mysql_extras/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timothyvanderaerden%2Fecto_mysql_extras/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timothyvanderaerden%2Fecto_mysql_extras/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timothyvanderaerden","download_url":"https://codeload.github.com/timothyvanderaerden/ecto_mysql_extras/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timothyvanderaerden%2Fecto_mysql_extras/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272582534,"owners_count":24959425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-28T02:00:10.768Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","ecto","elixir","mariadb","mysql"],"created_at":"2024-11-06T08:07:24.078Z","updated_at":"2025-08-28T23:49:26.134Z","avatar_url":"https://github.com/timothyvanderaerden.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ecto MySQL Extras\n\n[![CI](https://github.com/timothyvanderaerden/ecto_mysql_extras/actions/workflows/ci.yml/badge.svg)](https://github.com/timothyvanderaerden/ecto_mysql_extras/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/timothyvanderaerden/ecto_mysql_extras/branch/main/graph/badge.svg?token=IJMNEMI6CE)](https://codecov.io/gh/timothyvanderaerden/ecto_mysql_extras)\n[![Module Version](https://img.shields.io/hexpm/v/ecto_mysql_extras.svg)](https://hex.pm/packages/ecto_mysql_extras)\n[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/ecto_mysql_extras/)\n[![Total Download](https://img.shields.io/hexpm/dt/ecto_mysql_extras.svg)](https://hex.pm/packages/ecto_mysql_extras)\n[![License](https://img.shields.io/hexpm/l/ecto_mysql_extras.svg)](https://github.com/timothyvanderaerden/ecto_mysql_extras/blob/main/LICENSE)\n[![Last Updated](https://img.shields.io/github/last-commit/timothyvanderaerden/ecto_mysql_extras.svg)](https://github.com/timothyvanderaerden/ecto_mysql_extras/commits/main)\n\nThis library provides performance insight information on MySQL (and MariaDB) databases.\nIt's heavily based upon [Ecto PSQL Extras](https://github.com/pawurb/ecto_psql_extras), it reuses most of the design.\n\nThis library is an optional dependency of [Phoenix.LiveDashboard](https://hexdocs.pm/phoenix_live_dashboard/Phoenix.LiveDashboard.html).\n\n![Phoenix Ecto LiveDashboard](https://github.com/timothyvanderaerden/ecto_mysql_extras/raw/main/phoenix_live_dashboard.png)\n\nCurrently only `InnoDB` is supported, other engines may work but not all queries will return all or correct data.\n\nThe following databases are tested against:\n\n* MySQL \u003e= 8.0, \u003c= 8.4\n* MariaDB \u003e= 10.5, \u003c= 11.4\n\nOlder version may work but are not tested, newer version are tested every week to check for any compatibility issues.\n\n[![Test latest DB weekly](https://github.com/timothyvanderaerden/ecto_mysql_extras/actions/workflows/weekly-test.yml/badge.svg)](https://github.com/timothyvanderaerden/ecto_mysql_extras/actions/workflows/weekly-test.yml)\n\n## Installation\n\nThe package can be installed by adding `:ecto_mysql_extras` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:ecto_mysql_extras, \"~\u003e 0.6\"}\n  ]\nend\n```\n\n### MySQL/MariaDB configuration\n\nThe configured user should have read (SELECT) access on the `mysql`, `information_schema` and `performance_schema` database. Specifically for the following schemas:\n\n* `mysql.innodb_index_stats`\n* `performance_schema.table_io_waits_summary_by_index_usage`\n\nAn example on how to achieve this can be found in `docker/init/init.sql`.\n\n### Performance schema\n\nThe performance schema is enabled by default for MySQL databases but not for MariaDB. To enable this add `performance_schema=ON` to `my.cnf`. A restart is need to take effect.\n\nMore information: https://mariadb.com/kb/en/performance-schema-overview/\n\n## Usage\n\nTo run a query:\n\n```elixir\nEctoMySQLExtras.plugins(MyApp.Repo)\n```\nThis will return a `%MyXQL.Result{}` struct. If you want to display it in a more human readable (ASCII) way:\n\n```elixir\nEctoMySQLExtras.plugins(MyApp.Repo, format: :ascii)\n```\n\nBy default query logging is disabled, to enable logging you can do the following:\n```elixir\nEctoMySQLExtras.plugins(MyApp.Repo, query_opts: [log: true])\n```\n\nTo view all available queries:\n\n```elixir\nEctoMySQLExtras.queries()\n```\n\n### `connections`\n\n```\nEctoMySQLExtras.connections(MyApp.Repo, format: :ascii)\n\n+-------------------------------------------------------------------------------------+\n|                                  Active Connections                                 |\n+-----+------+-----------------+-------+---------+------+----------------------+------+\n| id  | user | host            | db    | command | time | state                | info |\n+-----+------+-----------------+-------+---------+------+----------------------+------+\n| 466 | root | localhost:49864 | my_db | Sleep   | 1    |                      |      |\n| 465 | root | localhost:49854 | my_db | Sleep   | 1    |                      |      |\n(truncated results for brevity)\n```\n\nShows all active connections.\n\n### `db_settings`\n\n```\nEctoMySQLExtras.db_settings(MyApp.Repo, format: :ascii)\n\n+--------------------------------------------+\n|           MySQL global variables           |\n+--------------------------------+-----------+\n| name                           | value     |\n+--------------------------------+-----------+\n| INNODB_BUFFER_POOL_INSTANCES   | 1         |\n| INNODB_BUFFER_POOL_SIZE        | 134217728 |\n(truncated results for brevity)\n```\n\nShows global variables for selected MySQL settings.\n\n### `db_status`\n\n```\nEctoMySQLExtras.db_status(MyApp.Repo, format: :ascii)\n\n+---------------------------------+\n|       MySQL global status       |\n+----------------------+----------+\n| name                 | value    |\n+----------------------+----------+\n| Aborted_clients      | 100      |\n| Aborted_connects     | 25       |\n(truncated results for brevity)\n```\n\nShows global status for selected MySQL server status.\n\n### `dirty_pages_ratio`\n\n```\nEctoMySQLExtras.dirty_pages_ratio(MyApp.Repo, format: :ascii)\n\n+------------------------------------+\n|      InnoDB Dirty Pages Ratio      |\n+----------------------+-------------+\n| ratio                | total_pages |\n+----------------------+-------------+\n| 0.024798512089274645 | \"8065\"      |\n+----------------------+-------------+\n```\n\nShows InnoDB dirty pages ratio.\nThe ratio of how often InnoDB needs to be flushed. During the write-heavy load, it is normal that this percentage increases.\nA good value should be 75% and below.\n\n### `index_size`\n\n```\nEctoMySQLExtras.index_size(MyApp.Repo, format: :ascii)\n\n+---------------------------------------------------+\n|      Size of the indexes, descending by size      |\n+----------+-------+-------------+-------+----------+\n| schema   | name  | index       | pages | size     |\n+----------+-------+-------------+-------+----------+\n| sportsdb | stats | IDX_stats_1 | 97    | 1.5 MB   |\n| sportsdb | stats | IDX_stats_5 | 23    | 368.0 KB |\n(truncated results for brevity)\n```\n\nShows the size of each index in the database, excluding primary keys. Additionally a table can be passed to only get indexes from that table.\n\n```\nEctoMySQLExtras.index_size(MyApp.Repo, format: :ascii, args: [table: \"my_table\"])\n```\n\n### `long_running_queries`\n\n```\nEctoMySQLExtras.long_running_queries(MyApp.Repo, format: :ascii)\n\n+------------------------------------------------------------------------------+\n|         All queries longer than the threshold by descending duration         |\n+----+--------+------+------+----------+-------+-------------+-----------------+\n| id | thread | user | host | duration | query | memory_used | max_memory_used |\n+----+--------+------+------+----------+-------+-------------+-----------------+\n(truncated results for brevity)\n```\n\nShows queries that have been running for longer than 0.5 seconds, descending by duration. The threshold can be configured and is represented in milliseconds, however for MySQL servers this is converted to seconds.\n\n```\nEctoMySQLExtras.long_running_queries(MyApp.Repo, format: :ascii, args: [threshold: 1000])\n```\n\n### `plugins`\n\n```\nEctoMySQLExtras.plugins(MyApp.Repo, format: :ascii)\n\n+--------------------------------------------------------------------------------------------------------------------------------------+\n|                                                     Available and installed plugins                                                  |\n+-----------------------+---------+--------+----------------+--------------------------------------------------------------------------+\n| name                  | version | status | type           | description                                                              |\n+-----------------------+---------+--------+----------------+--------------------------------------------------------------------------+\n| binlog                | 1.0     | ACTIVE | STORAGE ENGINE | This is a pseudo storage engine to represent the binlog in a transaction |\n| mysql_native_password | 1.0     | ACTIVE | AUTHENTICATION | Native MySQL authentication                                              |\n(truncated results for brevity)\n```\n\nShows all installed plugins, their version and status.\n\n### `records_rank`\n\n\n```\nEctoMySQLExtras.records_rank(MyApp.Repo, format: :ascii)\n\n+-----------------------------------------------------------------------------------------+\n|  All tables and the number of rows in each table ordered by number of rows descending   |\n+-------------+------------------------------------------+-----------+--------------------+\n| schema      | name                                     | engine    | estimated_count    |\n+-------------+------------------------------------------+-----------+--------------------+\n| sportsdb    | affiliations_events                      | InnoDB    | 13203              |\n| sportsdb    | participants_events                      | InnoDB    | 8533               |\n(truncated results for brevity)\n```\n\nShows an estimated count of rows per table, descending by estimated count. Additionally a table can be passed to only get an estimated count from that table.\n\n```\nEctoMySQLExtras.records_rank(MyApp.Repo, format: :ascii, args: [table: \"my_table\"])\n```\n\n### `table_cache`\n\n```\nEctoMySQLExtras.table_cache(MyApp.Repo, format: :ascii)\n\n+----------------------------------------+\n|           Table cache ratio            |\n+--------------------+-------------------+\n| cache_ratio        | hit_ratio         |\n+--------------------+-------------------+\n| 10.567458019687319 | 98.08219178082192 |\n+--------------------+-------------------+\n```\n\n- `cache_ratio`: The ratio of table cache usage for all threads.\n  A good value should be less than 80%. Increase the table_open_cache variable until the percentage reaches a good value.\n- `hit_ratio`: The ratio of table cache hit usage.\n  A good hit ratio value should be 90% and above. Otherwise, increase the table_open_cache variable until the hit ratio reaches a good value\n\n\n### `table_indexes_size`\n\n```\nEctoMySQLExtras.table_indexes_size(MyApp.Repo, format: :ascii)\n\n+------------------------------------------------------------------------------------------------+\n|  Total size of all the indexes on each table (excluding PRIMARY indexes), descending by size   |\n+----------------+---------------------------------------------+--------------+------------------+\n| schema         | name                                        | engine       | index_size       |\n+----------------+---------------------------------------------+--------------+------------------+\n| sportsdb       | stats                                       | InnoDB       | 3.3 MB           |\n| sportsdb       | participants_events                         | InnoDB       | 880.0 KB         |\n(truncated results for brevity)\n```\n\nShows the total size of all indexes in a table, descending by size. Primary indexes are not included. This also requires InnoDB as engine. Additionally a table can be passed to only get the total size of all indexes from that table.\n\n```\nEctoMySQLExtras.table_indexes_size(MyApp.Repo, format: :ascii, args: [table: \"my_table\"])\n```\n\n### `table_size`\n\n```\nEctoMySQLExtras.table_size(MyApp.Repo, format: :ascii)\n\n+----------------------------------------------------------------------+\n|      Size of the tables (excluding indexes), descending by size      |\n+----------+---------------------------------------+--------+----------+\n| schema   | name                                  | engine | size     |\n+----------+---------------------------------------+--------+----------+\n| sportsdb | stats                                 | InnoDB | 1.5 MB   |\n| sportsdb | participants_events                   | InnoDB | 496.0 KB |\n(truncated results for brevity)\n```\n\nShows the table size of each table in the database excluding indexes, descending by size. Additionally a table can be passed to only get the size from that table.\n\n```\nEctoMySQLExtras.table_size(MyApp.Repo, format: :ascii, args: [table: \"my_table\"])\n```\n\n### `total_index_size`\n\n```\nEctoMySQLExtras.total_index_size(MyApp.Repo, format: :ascii)\n\n+-------------------------------------------------------------+\n| Total size of all indexes (excluding PRIMARY indexes) in MB |\n+-------------------------------------------------------------+\n| size                                                        |\n+-------------------------------------------------------------+\n| 9.8 MB                                                      |\n+-------------------------------------------------------------+\n```\n\nShows the total index size of all tables in the database, primary indexes are not included.\n\n### `total_table_size`\n\n```\nEctoMySQLExtras.total_table_size(MyApp.Repo, format: :ascii)\n\n+----------------------------------------------------------------------+\n|      Size of the tables (including indexes), descending by size      |\n+----------+---------------------------------------+--------+----------+\n| schema   | name                                  | engine | size     |\n+----------+---------------------------------------+--------+----------+\n| sportsdb | stats                                 | InnoDB | 4.8 MB   |\n| sportsdb | participants_events                   | InnoDB | 1.3 MB   |\n(truncated results for brevity)\n```\n\nShows the total table size of each table in the database including indexes, descending by size. Additionally a table can be passed to only get the total size from that table.\n\n```\nEctoMySQLExtras.total_table_size(MyApp.Repo, format: :ascii, args: [table: \"my_table\"])\n```\n\n### `unused_indexes`\n\n```\nEctoMySQLExtras.unused_indexes(MyApp.Repo, format: :ascii)\n\n+-----------------------------------------------------------------------------------------------------------------+\n|                                        Unused and almost unused indexes                                         |\n+----------+--------------------------+-------------------------------------------+-------+----------+------------+\n| schema   | table                    | index                                     | pages | size     | index_hits |\n+----------+--------------------------+-------------------------------------------+-------+----------+------------+\n| sportsdb | stats                    | IDX_stats_1                               | 97    | 1.5 MB   | 0          |\n| sportsdb | events                   | IDX_FK_eve_pub_id__pub_id                 | 6     | 96.0 KB  | 0          |\n(truncated results for brevity)\n```\n\nShows all the indexes that are not used, the database should be running for a while to have the best results since it's based upon IO activity. This also requires InnoDB as engine.\n\n### `waits_for_checkpoint`\n\n```\nEctoMySQLExtras.waits_for_checkpoint(MyApp.Repo, format: :ascii)\n\n+--------------------------------------------------------------------------------------------------+\n| The ratio of how often InnoDB needs to read or create a page where no clean pages are available  |\n+---------------------------------------------+----------------------------------------------------+\n| ratio                                       | wait_counter                                       |\n+---------------------------------------------+----------------------------------------------------+\n| 0.0                                         | \"0\"                                                |\n+---------------------------------------------+----------------------------------------------------+\n```\n\nShows the ratio of how often InnoDB needs to read or create a page where no clean pages are available.\nA good ratio value should stay below 1. If `wait_counter` is greater than 0, it is a strong indicator that the InnoDB buffer pool is too small,\nand operations had to wait on a checkpoint.\n\n### `waits_for_redolog`\n\n```\nEctoMySQLExtras.waits_for_redolog(MyApp.Repo, format: :ascii)\n\n+----------------------------------+\n| The ratio of redo log contention |\n+-------------+--------------------+\n| ratio       | wait_counter       |\n+-------------+--------------------+\n| 0.0         | \"0\"                |\n+-------------+--------------------+\n```\n\nShows the ratio of redo log contention. A good ratio value should stay below 1.\nCheck `wait_counter` and if it continues to increase then it is a strong indicator that the InnoDB buffer pool is too small.\nIt can also mean that the disks are too slow and cannot sustain the disk IO, perhaps due to peak write load.\n\n\u003e #### Note {: .info}\n\u003e\n\u003e Some queries use the `information_schema` table which can cause performance issues when executing on a busy system. Use the `performance_schema` where possible, depending on the version and database this might not be available.\n\n## Ecto MySQL Extras differences\n\nExcept for the \"obvious\" difference that `Ecto MySQL Extras` provides information on MySQL (MariaDB) databases and `Ecto PSQL Extras` on PostgreSQL databases, there are some small differences. Below is a list which could be useful if you're already using `Ecto PSQL Extras` and want to try `Ecto MySQL Extras`.\n\n* `:table_rex` is an optional dependency.\n* The default format is `:raw` instead of `:ascii`.\n\n## Query sources\n\n- https://severalnines.com/database-blog/monitoring-percona-server-mysql-key-metrics\n\n## Copyright and License\n\nCopyright (c) 2021 Timothy Vanderaerden\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0).\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimothyvanderaerden%2Fecto_mysql_extras","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimothyvanderaerden%2Fecto_mysql_extras","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimothyvanderaerden%2Fecto_mysql_extras/lists"}