Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[9.x] New db:show, db:table and db:monitor commands #43367

Merged
merged 31 commits into from Aug 2, 2022
Merged

Conversation

jbrooksuk
Copy link
Member

@jbrooksuk jbrooksuk commented Jul 22, 2022

This PR adds three new Artisan commands which provide information about the database directly from a Laravel project.

In summary, it exposes information such as:

  • A list of all tables with row count and table size
  • Overall size of the database
  • Current number of database connections
  • Column types
  • List of indexes
  • List of foreign keys and table references
  • Ability to monitor the database and listen for events when the database is under load

db:show

This command gives you an overview of the database as a whole. Out of the box, it will utilise your default connection, but you may optionally choose the connection you wish to inspect.

Upon running the command, you will see a summary of the database including database type, connection details, number of connections, total rows and overall size.

You will also see a breakdown of tables including table size and optionally (using the --with-counts option), the number of rows. This is an option as it can be an expensive operation on larger databases.

Additionally, using the --with-views option, you may also see a summary of the database views.

The output for this command is also available in JSON using the --json option.

Example JSON
{
  "platform": {
    "config": {
      "driver": "mysql",
      "url": null,
      "host": "127.0.0.1",
      "port": "3306",
      "database": "vapor_app",
      "username": "root",
      "unix_socket": "",
      "charset": "utf8mb4",
      "collation": "utf8mb4_unicode_ci",
      "prefix": "",
      "prefix_indexes": true,
      "strict": true,
      "engine": null,
      "options": []
    },
    "name": "MySQL 8",
    "open_connections": 2
  },
  "tables": [
    {
      "table": "failed_jobs",
      "size": 16384,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    },
    {
      "table": "migrations",
      "size": 16384,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    },
    {
      "table": "password_resets",
      "size": 16384,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    },
    {
      "table": "personal_access_tokens",
      "size": 16384,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    },
    {
      "table": "posts",
      "size": 32768,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    },
    {
      "table": "users",
      "size": 16384,
      "rows": null,
      "engine": "InnoDB",
      "comment": ""
    }
  ]
}

This command is really useful to get a better understanding of the health of your database.

Example db:show command


db:table

Where db:show allows you to see the state of a database as a whole, db:table allows you to see the state of an individual table by passing the table name as an argument or selecting the table from the list of tables provided.

As with db:show, the command will use your default database connection, but you may pass the connection you wish to use.

This command provides a summary of the table including the size and number of rows as well as a breakdown of every column along with its attributes and data type.

Additionally, it presents an overview of all indexes and foreign keys including the columns and tables referenced. It’s a great way to get a better understanding of a given table and how it relates to others.

The output for this command is also available in JSON using the --json option.

Example JSON
{
  "table": {
    "name": "posts",
    "columns": 4,
    "size": 32768
  },
  "columns": {
    "id": {
      "column": "id",
      "attributes": {
        "0": "autoincrement",
        "type": "bigint",
        "1": "unsigned"
      },
      "default": null,
      "type": "bigint"
    },
    "user_id": {
      "column": "user_id",
      "attributes": {
        "type": "bigint",
        "1": "unsigned"
      },
      "default": null,
      "type": "bigint"
    },
    "created_at": {
      "column": "created_at",
      "attributes": {
        "type": "datetime",
        "2": "nullable"
      },
      "default": null,
      "type": "datetime"
    },
    "updated_at": {
      "column": "updated_at",
      "attributes": {
        "type": "datetime",
        "2": "nullable"
      },
      "default": null,
      "type": "datetime"
    }
  },
  "indexes": {
    "posts_user_id_foreign": {
      "name": "posts_user_id_foreign",
      "columns": [
        "user_id"
      ],
      "attributes": []
    },
    "primary": {
      "name": "PRIMARY",
      "columns": [
        "id"
      ],
      "attributes": [
        "unique",
        "primary"
      ]
    }
  },
  "foreign_keys": {
    "posts_user_id_foreign": {
      "name": "posts_user_id_foreign",
      "local_table": "posts",
      "local_columns": [
        "user_id"
      ],
      "foreign_table": "users",
      "foreign_columns": [
        "id"
      ],
      "on_update": "no action",
      "on_delete": "cascade"
    }
  }
}

Example db:table command


db:monitor

Much like the queue:monitor command, db:monitor allows you to quickly see the number of connections your database is handling, which is a great indicator of the load it is currently under.

In addition, you may pass the --max option which will dispatch a DatabaseBusy event when the number of connections is ≥ the max provided. If no --max value is provided, no events will be dispatched. Your application may listen for this event in order to, for instance, send an email to the operations team notifying them the database is under strain.

Typically, this would be run as a scheduled command as often as you would like the check to be carried out.

Example db:monitor command

@SuperDJ
Copy link
Contributor

SuperDJ commented Jul 24, 2022

Would this also show table check constraints?

@joedixon joedixon changed the title [9.x] New db:monitor, db:show and db:table commands [9.x] New db:show, db:table and db:monitor commands Jul 24, 2022
@jbrooksuk jbrooksuk marked this pull request as ready for review Jul 25, 2022
@jbrooksuk
Copy link
Member Author

jbrooksuk commented Jul 25, 2022

Would this also show table check constraints?

Not currently it doesn't.

@driesvints
Copy link
Member

driesvints commented Jul 26, 2022

I want to suggest to keep database as an option as that's by far the most frequently used way of doing that across our commands.

@timacdonald
Copy link
Member

timacdonald commented Jul 26, 2022

I feel like the db:table command data may potentially be better off incorporated into the model:show command. I know at one point @jessarcher had the command showing the index info behind a verbose flag, at which point they feel kinda identical - but the db version doesn't show model related stuff as well.

I get that there might be tables that are not backed by a model, but just wanted to make that suggestion.

Co-authored-by: bastien-phi <bastien.philippe@soyhuce.fr>
@jbrooksuk
Copy link
Member Author

jbrooksuk commented Jul 27, 2022

@timacdonald the way @joedixon and I see this command is that db: is more for production use. You're probably not too interested in what a model looks like when you're on a production server, but you do want to know what's going on with the tables - it's like TablePlus in your Terminal.

@imManish
Copy link

imManish commented Jul 30, 2022

@jbrooksuk - What if migrations are not present, and framework directly connect with remote database on production. db:show able to show the schema of the database. hope this works with remotely connected database though.

@driesvints
Copy link
Member

driesvints commented Aug 1, 2022

@timacdonald there's still Laravel apps that don't use Eloquent and just use the database query builder to perform database operations. In that regard it makes sense to me to keep db:table separately so you have the least amount of abstraction.

@jbrooksuk
Copy link
Member Author

jbrooksuk commented Aug 1, 2022

@jbrooksuk - What if migrations are not present, and framework directly connect with remote database on production. db:show able to show the schema of the database. hope this works with remotely connected database though.

This isn't using migrations to generate the output. It's essentially connecting to your database directly (from the database.php configuration) to dump out information.

@imManish
Copy link

imManish commented Aug 1, 2022

information

@jbrooksuk - I understand that! but the concern is if the app connected with multiple database such as DB1 and DB2 will is there any option that i have to parse along with command db:show --name=db1,db:monitor --name=db1 ,db:table --name=db1 i guess it should have work like this.

could you let us know show it will work with multiple database connection. can't we have it within model which would have connection property which will display which model connected with which database and will display accordingly.

@joedixon
Copy link
Contributor

joedixon commented Aug 1, 2022

@jbrooksuk - I understand that! but the concern is if the app connected with multiple database such as DB1 and DB2 will is there any option that i have to parse along with command db:show --name=db1,db:monitor --name=db1 ,db:table --name=db1 i guess it should have work like this.

could you let us know show it will work with multiple database connection. can't we have it within model which would have connection property which will display which model connected with which database and will display accordingly.

Hi @imManish - This set of commands doesn't have any relation to models. It specifically allows you to get a snapshot of a single database/table. The commands will use your default connection, however you are free to choose which database you which to inspect by using the --database option.

@taylorotwell taylorotwell merged commit 47a4eb4 into 9.x Aug 2, 2022
32 checks passed
@taylorotwell taylorotwell deleted the feat/db-commands branch Aug 2, 2022
Ken-vdE pushed a commit to Ken-vdE/framework that referenced this pull request Aug 9, 2022
)

* wip

* wip

* wip

* wip

* wip

* wip

* Create `AbstractDatabaseCommand`

* wip

* Change return type of connection count methods

* Add `db:monitor`

* Move dbal check

* Formatting

* Opt-in to expensive operations

* Apply fixes from StyleCI

* Ask for table

* Rename variable

* Change how getTableSize works

* Make `--max` optional in `db:monitor`

* wip

* Standardise headings

* make `db:monitor` use an argument for databases

* Use option again

* Move composer to abstract

* Add composer

* Apply fixes from StyleCI

* Update src/Illuminate/Database/Console/MonitorCommand.php

Co-authored-by: bastien-phi <bastien.philippe@soyhuce.fr>

* formatting

* Apply fixes from StyleCI

Co-authored-by: Joe Dixon <hello@joedixon.co.uk>
Co-authored-by: StyleCI Bot <bot@styleci.io>
Co-authored-by: Dries Vints <dries@vints.io>
Co-authored-by: bastien-phi <bastien.philippe@soyhuce.fr>
Co-authored-by: Taylor Otwell <taylor@laravel.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants