MySQL

Topics related to MySQL:

Getting started with MySQL

MySQL Logo

MySQL is an open-source Relational Database Management System (RDBMS) that is developed and supported by Oracle Corporation.

MySQL is supported on a large number of platforms, including Linux variants, OS X, and Windows. It also has APIs for a large number of languages, including C, C++, Java, Lua, .Net, Perl, PHP, Python, and Ruby.

MariaDB is a fork of MySQL with a slightly different feature set. It is entirely compatible with MySQL for most applications.

Limit and Offset

"Limit" could mean "Max number of rows in a table".

"Offset" mean pick from row number (not to be confused by primary key value or any field data value)

Creating databases

Backup using mysqldump

The output of a mysqldump operation is a lightly commented file containing sequential SQL statements that are compatible with the version of MySQL utilities that was used to generate it (with attention paid to compatibility with previous versions, but no guarantee for future ones). Thus, the restoration of a mysqldumped database comprises execution of those statements. Generally, this file

  • DROPs the first specified table or view
  • CREATEs that table or view
  • For tables dumped with data (i.e. without the --no-data option)
    • LOCKs the table
    • INSERTs all of the rows from the original table in one statement
  • UNLOCK TABLES
  • Repeats the above for all other tables and views
  • DROPs the first included routine
  • CREATEs that routine
  • Repeats the same for all other routines

The presence of the DROP before CREATE for each table means that if the schema is present, whether or not it is empty, using a mysqldump file for its restoration will populate or overwrite the data therein.

Table Creation

INSERT

Error codes

Stored routines (procedures and functions)

A stored routine is either a procedure or a function.

A procedure is invoked using a CALL statement and can only pass back values using output variables.

A function can be called from inside a statement just like any other function and can return a scalar value.

Reserved Words

Listed below are all reserved words (from the official documentation):

  • ACCESSIBLE
  • ADD
  • ALL
  • ALTER
  • ANALYZE
  • AND
  • AS
  • ASC
  • ASENSITIVE
  • BEFORE
  • BETWEEN
  • BIGINT
  • BINARY
  • BLOB
  • BOTH
  • BY
  • CALL
  • CASCADE
  • CASE
  • CHANGE
  • CHAR
  • CHARACTER
  • CHECK
  • COLLATE
  • COLUMN
  • CONDITION
  • CONSTRAINT
  • CONTINUE
  • CONVERT
  • CREATE
  • CROSS
  • CURRENT_DATE
  • CURRENT_TIME
  • CURRENT_TIMESTAMP
  • CURRENT_USER
  • CURSOR
  • DATABASE
  • DATABASES
  • DAY_HOUR
  • DAY_MICROSECOND
  • DAY_MINUTE
  • DAY_SECOND
  • DEC
  • DECIMAL
  • DECLARE
  • DEFAULT
  • DELAYED
  • DELETE
  • DESC
  • DESCRIBE
  • DETERMINISTIC
  • DISTINCT
  • DISTINCTROW
  • DIV
  • DOUBLE
  • DROP
  • DUAL
  • EACH
  • ELSE
  • ELSEIF
  • ENCLOSED
  • ESCAPED
  • EXISTS
  • EXIT
  • EXPLAIN
  • FALSE
  • FETCH
  • FLOAT
  • FLOAT4
  • FLOAT8
  • FOR
  • FORCE
  • FOREIGN
  • FROM
  • FULLTEXT
  • GENERATED
  • GET
  • GRANT
  • GROUP
  • HAVING
  • HIGH_PRIORITY
  • HOUR_MICROSECOND
  • HOUR_MINUTE
  • HOUR_SECOND
  • IF
  • IGNORE
  • IN
  • INDEX
  • INFILE
  • INNER
  • INOUT
  • INSENSITIVE
  • INSERT
  • INT
  • INT1
  • INT2
  • INT3
  • INT4
  • INT8
  • INTEGER
  • INTERVAL
  • INTO
  • IO_AFTER_GTIDS
  • IO_BEFORE_GTIDS
  • IS
  • ITERATE
  • JOIN
  • KEY
  • KEYS
  • KILL
  • LEADING
  • LEAVE
  • LEFT
  • LIKE
  • LIMIT
  • LINEAR
  • LINES
  • LOAD
  • LOCALTIME
  • LOCALTIMESTAMP
  • LOCK
  • LONG
  • LONGBLOB
  • LONGTEXT
  • LOOP
  • LOW_PRIORITY
  • MASTER_BIND
  • MASTER_SSL_VERIFY_SERVER_CERT
  • MATCH
  • MAXVALUE
  • MEDIUMBLOB
  • MEDIUMINT
  • MEDIUMTEXT
  • MIDDLEINT
  • MINUTE_MICROSECOND
  • MINUTE_SECOND
  • MOD
  • MODIFIES
  • NATURAL
  • NOT
  • NO_WRITE_TO_BINLOG
  • NULL
  • NUMERIC
  • ON
  • OPTIMIZE
  • OPTIMIZER_COSTS
  • OPTION
  • OPTIONALLY
  • OR
  • ORDER
  • OUT
  • OUTER
  • OUTFILE
  • PARTITION
  • PRECISION
  • PRIMARY
  • PROCEDURE
  • PURGE
  • RANGE
  • READ
  • READS
  • READ_WRITE
  • REAL
  • REFERENCES
  • REGEXP
  • RELEASE
  • RENAME
  • REPEAT
  • REPLACE
  • REQUIRE
  • RESIGNAL
  • RESTRICT
  • RETURN
  • REVOKE
  • RIGHT
  • RLIKE
  • SCHEMA
  • SCHEMAS
  • SECOND_MICROSECOND
  • SELECT
  • SENSITIVE
  • SEPARATOR
  • SET
  • SHOW
  • SIGNAL
  • SMALLINT
  • SPATIAL
  • SPECIFIC
  • SQL
  • SQLEXCEPTION
  • SQLSTATE
  • SQLWARNING
  • SQL_BIG_RESULT
  • SQL_CALC_FOUND_ROWS
  • SQL_SMALL_RESULT
  • SSL
  • STARTING
  • STORED
  • STRAIGHT_JOIN
  • TABLE
  • TERMINATED
  • THEN
  • TINYBLOB
  • TINYINT
  • TINYTEXT
  • TO
  • TRAILING
  • TRIGGER
  • TRUE
  • UNDO
  • UNION
  • UNIQUE
  • UNLOCK
  • UNSIGNED
  • UPDATE
  • USAGE
  • USE
  • USING
  • UTC_DATE
  • UTC_TIME
  • UTC_TIMESTAMP
  • VALUES
  • VARBINARY
  • VARCHAR
  • VARCHARACTER
  • VARYING
  • VIRTUAL
  • WHEN
  • WHERE
  • WHILE
  • WITH
  • WRITE
  • XOR
  • YEAR_MONTH
  • ZEROFILL
  • GENERATED
  • OPTIMIZER_COSTS
  • STORED
  • VIRTUAL

String operations

DELETE

VIEW

Views are virtual tables and do not contain the data that is returned. They can save you from writing complex queries again and again.

  • Before a view is made its specification consists entirely of a SELECT statement. The SELECT statement cannot contain a sub-query in the FROM clause.
  • Once a view is made it is used largely just like a table and can be SELECTed from just like a table.

You have to create views, when you want to restrict few columns of your table, from the other user.

  • For example: In your organization, you want your managers to view few information from a table named-"Sales", but you don't want that your software engineers can view all fields of table-"Sales". Here, you can create two different views for your managers and your software engineers.

Performance. VIEWs are syntactic sugar. However there performance may or may not be worse than the equivalent query with the view's select folded in. The Optimizer attempts to do this "fold in" for you, but is not always successful. MySQL 5.7.6 provides some more enhancements in the Optimizer. But, regardless, using a VIEW will not generate a faster query.

Indexes and Keys

Concepts

An index in a MySQL table works like an index in a book.

Let's say you have a book about databases and you want to find some information about, say, storage. Without an index (assuming no other aid, such as a table of contents) you'd have to go through the pages one by one, until you found the topic (that's a "full table scan"). On the other hand, an index has a list of keywords, so you'd consult the index and see that storage is mentioned on pages 113-120, 231, and 354. Then you could flip to those pages directly, without searching (that's a search with an index, somewhat faster).

Of course, the usefulness of the index depends on many things - a few examples, using the simile above:

  • If you had a book on databases and indexed the word "database", you might see that it's mentioned on pages 1-59, 61-290, and 292-400. That's a lot of pages, and in such a case, the index is not much help and it might be faster to go through the pages one by one. (In a database, this is "poor selectivity".)
  • For a 10-page book, it makes no sense to make an index, as you may end up with a 10-page book prefixed by a 5-page index, which is just silly - just scan the 10 pages and be done with it.
  • The index also needs to be useful - there's generally no point to indexing, for example, the frequency of the letter "L" per page.

Date and Time Operations

Comment Mysql

LOAD DATA INFILE

PREPARE Statements

ALTER TABLE

    alter_specification: table_options
      | ADD [COLUMN] col_name column_definition [FIRST | AFTER col_name ]
      | ADD [COLUMN] (col_name column_definition,...)
      | ADD {INDEX|KEY} [index_name] [index_type] (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name] [index_type] (index_col_name,...) [index_option] ...
      | ADD FULLTEXT [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ...
      | ADD SPATIAL [INDEX|KEY] [index_name] (index_col_name,...) [index_option] ...
      | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,...) reference_definition
      | ALGORITHM [=] {DEFAULT|INPLACE|COPY}
      | ALTER [COLUMN] col_name {SET DEFAULT literal | DROP DEFAULT}
      | CHANGE [COLUMN] old_col_name new_col_name column_definition [FIRST|AFTER col_name]
      | LOCK [=] {DEFAULT|NONE|SHARED|EXCLUSIVE}
      | MODIFY [COLUMN] col_name column_definition [FIRST | AFTER col_name]
      | DROP [COLUMN] col_name
      | DROP PRIMARY KEY
      | DROP {INDEX|KEY} index_name
      | DROP FOREIGN KEY fk_symbol
      | DISABLE KEYS
      | ENABLE KEYS
      | RENAME [TO|AS] new_tbl_name
      | RENAME {INDEX|KEY} old_index_name TO new_index_name
      | ORDER BY col_name [, col_name] ...
      | CONVERT TO CHARACTER SET charset_name [COLLATE collation_name]
      | [DEFAULT] CHARACTER SET [=] charset_name [COLLATE [=] collation_name]
      | DISCARD TABLESPACE
      | IMPORT TABLESPACE
      | FORCE
      | {WITHOUT|WITH} VALIDATION
      | ADD PARTITION (partition_definition)
      | DROP PARTITION partition_names
      | DISCARD PARTITION {partition_names | ALL} TABLESPACE
      | IMPORT PARTITION {partition_names | ALL} TABLESPACE
      | TRUNCATE PARTITION {partition_names | ALL}
      | COALESCE PARTITION number
      | REORGANIZE PARTITION partition_names INTO (partition_definitions)
      | EXCHANGE PARTITION partition_name WITH TABLE tbl_name [{WITH|WITHOUT} VALIDATION]
      | ANALYZE PARTITION {partition_names | ALL}
      | CHECK PARTITION {partition_names | ALL}
      | OPTIMIZE PARTITION {partition_names | ALL}
      | REBUILD PARTITION {partition_names | ALL}
      | REPAIR PARTITION {partition_names | ALL}
      | REMOVE PARTITIONING
      | UPGRADE PARTITIONING
   index_col_name: col_name [(length)] [ASC | DESC]
   index_type: USING {BTREE | HASH}
   index_option: KEY_BLOCK_SIZE [=] value
      | index_type
      | WITH PARSER parser_name
      | COMMENT 'string'

table_options: table_option [[,] table_option] ... (see CREATE TABLE options)

partition_options: (see CREATE TABLE options)

Ref: MySQL 5.7 Reference Manual / ... / ALTER TABLE Syntax / 14.1.8 ALTER TABLE Syntax

Joins

UPDATE

Change Password

JSON

Starting from MySQL 5.7.8, MySQL ships with a JSON type. Lots of devs have been saving JSON data in text columns for a log time but the JSON type is different, the data is saved in binary format after validation. That avoids the overhead of parsing the text on each read.

MySQL Admin

TRIGGERS

Two points need to draw your attention if you already use triggers on others DB :

FOR EACH ROW

FOR EACH ROW is a mandatory part of the syntax

You can't make a statement trigger (once by query) like Oracle do. It's more a performance related issue than a real missing feature

CREATE OR REPLACE TRIGGER

The CREATE OR REPLACE is not supported by MySQL

MySQL don't allow this syntax, you have instead to use the following :

DELIMITER $$

DROP TRIGGER IF EXISTS myTrigger;
$$
CREATE TRIGGER myTrigger
-- ...

$$
DELIMITER ;

Be careful, this is not an atomic transaction :

  • you'll loose the old trigger if the CREATE fail
  • on a heavy load, others operations can occurs between the DROP and the CREATE, use a LOCK TABLES myTable WRITE; first to avoid data inconsistency and UNLOCK TABLES; after the CREATE to release the table

Pivot queries

Pivot query creation in MySQL relies upon the GROUP_CONCAT() function. If the result of the expression that creates the columns of the pivot query is expected to be large, the value of the group_concat_max_len variable must be increased:

set session group_concat_max_len = 1024 * 1024; -- This should be enough for most cases

Configuration and tuning

Configuration happens in one of 3 ways:

  • command line options
  • the my.cnf configuration file
  • setting variables from within the server

Command Line options takes the form mysqld --long-parameter-name=value --another-parameter. The same parameters can be placed in the my.conf configuration file. Some parameters are configurable using system variables from within MySQL. Check the official documentation for a complete list of parameters.

Variables can have dash - or underscore _. Spaces may exist around the =. Large numbers can be suffixed by K, M, G for kilo-, mega-, and giga-. One setting per line.

Flags: Usually ON and 1 are synonymous, ditto for OFF and 0. Some flags have nothing after them.

When placing the settings in my.cnf, all settings for the server must be in the [mysqld] section, so don't blindly add settings to the end of the file. (Note: For tools that allow multiple mysql instances to share one my.cnf, the section names may be different.)

Converting from MyISAM to InnoDB

SELECT

Create New User

To view a List of MySQL Users, we use the following command :

SELECT User,Host FROM mysql.user;

Group By

The MySQL GROUP BY clause is used in a SELECT statement to collect data across multiple records and group the results by one or more columns.

Its behavior is governed in part by the value of the ONLY_FULL_GROUP_BY variable. When this is enabled, SELECT statements that group by any column not in the output return an error. (This is the default as of 5.7.5.) Both setting and not setting this variable can cause problems for naive users or users accustomed to other DBMSs.

UNION

UNION does not use multiple CPUs.

UNION always* involves a temp table to collect the results. *As of 5.7.3 / MariaDB 10.1, some forms of UNION deliver the results without using a tmp table (hence, faster).

Drop Table

Data Types

Performance Tuning

Events

ENUM

Install Mysql container with Docker-Compose

Arithmetic

MySQL, on most machines, uses 64-bit IEEE 754 floating point arithmetic for its calculations.

In integer contexts it uses integer arithmetic.

  • RAND() is not a perfect random number generator. It is mainly used to quickly generate pseudorandom numbers

Character Sets and Collations

MyISAM Engine

Over the years, InnoDB has improved to the point where it is almost always better than MyISAM, at least the currently supported versions. Bottom line: Don't use MyISAM, except maybe for tables that are truly temporary.

One advantage of MyISAM over InnoDB remains: It is 2x-3x smaller in space required on disk.

When InnoDB first came out, MyISAM was still a viable Engine. But with the advent of XtraDB and 5.6, InnoDB became "better" than MyISAM in most benchmarks.

Rumor has it that the next major version will eliminate the need for MyISAM by making truly temporary InnoDB tables and by moving the system tables into InnoDB.

Many-to-many Mapping table

  • Lack of an AUTO_INCREMENT id for this table -- The PK given is the 'natural' PK; there is no good reason for a surrogate.
  • MEDIUMINT -- This is a reminder that all INTs should be made as small as is safe (smaller ⇒ faster). Of course the declaration here must match the definition in the table being linked to.
  • UNSIGNED -- Nearly all INTs may as well be declared non-negative
  • NOT NULL -- Well, that's true, isn't it?
  • InnoDB -- More effecient than MyISAM because of the way the PRIMARY KEY is clustered with the data in InnoDB.
  • INDEX(y_id, x_id) -- The PRIMARY KEY makes it efficient to go one direction; the makes the other direction efficient. No need to say UNIQUE; that would be extra effort on INSERTs.
  • In the secondary index, saying just INDEX(y_id) would work because it would implicit include x_id. But I would rather make it more obvious that I am hoping for a 'covering' index.

You may want to add more columns to the table; this is rare. The extra columns could provide information about the relationship that the table represents.

You may want to add FOREIGN KEY constraints.

Using Variables

Log files

Partitioning

  • RANGE partitioning. This type of partitioning assigns rows to partitions based on column values falling within a given range.

  • LIST partitioning. Similar to partitioning by RANGE, except that the partition is selected based on columns matching one of a set of discrete values.

  • HASH partitioning. With this type of partitioning, a partition is selected based on the value returned by a user-defined expression that operates on column values in rows to be inserted into the table. The function may consist of any expression valid in MySQL that yields a nonnegative integer value. An extension to this type, LINEAR HASH, is also available.

  • KEY partitioning. This type of partitioning is similar to partitioning by HASH, except that only one or more columns to be evaluated are supplied, and the MySQL server provides its own hashing function. These columns can contain other than integer values, since the hashing function supplied by MySQL guarantees an integer result regardless of the column data type. An extension to this type, LINEAR KEY, is also available.

Clustering

Security via GRANTs

Backticks

mysqlimport

mysqlimport will use the name of the imported file, after stripping the extension, to determine the destination table.

MySQL LOCK TABLE

MySQL Unions

UNION DISTINCT is the same as UNION; it is slower than UNION ALL because of a de-duplicating pass. A good practice is to always spell out DISTINCT or ALL, thereby signaling that you thought about which to do.

ORDER BY

MySQL client

Mysql Performance Tips

Temporary Tables

Transaction

Customize PS1

Dealing with sparse or missing data

Dynamic Un-Pivot Table using Prepared Statement

NULL

Replication

Replication is used to copy[Backup] data from one MySQL database server to one or more MySQL database servers.

Master -- The MySQL database server, which is serving data to be copied

Slave -- The MySQL database server, copies data which is served by Master

With MySQL, replication is asynchronous by default. This means slaves do not need to be connected permanently to receive updates from the master. For example, if your slave is switched OFF or not connected with master and you are switching slave ON or connect with Master at a later time, then it will automatically synchronize with the Master.

Depending on the configuration, you can replicate all databases, selected databases, or even selected tables within a database.

Replication Formats

There are two core types of replication formats

Statement Based Replication (SBR) -- which replicates entire SQL statements. In this, the master writes SQL statements to the binary log. Replication of the master to the slave works by executing that SQL statements on the slave.

Row Based Replication (RBR) -- which replicates only the changed rows. In this, the master writes events to the binary log that indicate how individual table rows are changed. Replication of the master to the slave works by copying the events representing the changes to the table rows to the slave.

You can also use a third variety, Mixed Based Replication (MBR). In this, both statement-based and row-based logging is used. Log will be created depending on which is most appropriate for the change.

Statement-based format was the default in MySQL versions older than 5.7.7. In MySQL 5.7.7 and later, row-based format is the default.

Connecting with UTF-8 Using Various Programming language.

SSL Connection Setup

Handling Time Zones

When you need to handle time information for a worldwide user base in MySQL, use the TIMESTAMP data type in your tables.

For each user, store a user-preference timezone column. VARCHAR(64) is a good data type for that column. When a user registers to use your system, ask for the time zone value. Mine is Atlantic Time, America/Edmonton. Yours might or might not be Asia/Kolkata or Australia/NSW. For a user interface for this user-preference setting, the WordPress.org software has a good example.

Finally, whenever you establish a connection from your host program (Java, php, whatever) to your DBMS on behalf of a user, issue the SQL command

 SET SESSION time_zone='(whatever tz string the user gave you)'

before you handle any user data involving times. Then all the TIMESTAMP times you have install will render in the user's local time.

This will cause all times going in to your tables to be converted to UTC, and all times coming out to be translated to local. It works properly for NOW() and CURDATE(). Again, you must use TIMESTAMP and not DATETIME or DATE data types for this.

Make sure your server OS and default MySQL time zones are set to UTC. If you don't do this before you start loading information into your database, it will be almost impossible to fix. If you use a vendor to run MySQL, insist they get this right.

Time with subsecond precision

You need to be at MySQL version 5.6.4 or later to declare columns with fractional-second time datatypes.

For example, DATETIME(3) will give you millisecond resolution in your timestamps, and TIMESTAMP(6) will give you microsecond resolution on a *nix-style timestamp.

Read this: http://dev.mysql.com/doc/refman/5.7/en/fractional-seconds.html

NOW(3) will give you the present time from your MySQL server's operating system with millisecond precision.

(Notice that MySQL internal fractional arithmetic, like * 0.001, is always handled as IEEE754 double precision floating point, so it's unlikely you'll lose precision before the Sun becomes a white dwarf star.)

Error 1055: ONLY_FULL_GROUP_BY: something is not in GROUP BY clause ...

For a long time now, MySQL has contained a notorious nonstandard extension to GROUP BY, which allows oddball behavior in the name of efficiency. This extension has allowed countless developers around the world to use GROUP BY in production code without completely understanding what they were doing.

In particular, it's a bad idea to use SELECT * in a GROUP BY query, because a standard GROUP BY clause requires enumerating the columns. Many developers have, unfortunately, done that.

Read this. https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

The MySQL team has been trying to fix this misfeature without messing up production code. They added a sql_mode flag in 5.7.5 named ONLY_FULL_GROUP_BY to compel standard behavior. In a recent release, they turned on that flag by default. When you upgraded your local MySQL to 5.7.14, the flag got switched on and your production code, dependent on the old extension, stopped working.

If you've recently started getting 1055 errors, what are your choices?

  1. fix the offending SQL queries, or get their authors to do that.
  2. roll back to a version of MySQL compatible out-of-the-box with the application software you use.
  3. change your server's sql_mode to get rid of the newly set ONLY_FULL_GROUP_BY mode.

You can change the mode by doing a SET command.

SET  sql_mode = 'STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'

should do the trick if you do it right after your application connects to MySQL.

Or, you can find the init file in your MySQL installation, locate the sql_mode= line, and change it to omit ONLY_FULL_GROUP_BY, and restart your server.

Full-Text search

FULLTEXT searching works strangely on tables containing small numbers of rows. So, when you're experimenting with it, you may find it helpful to obtain a medium-sized table online. Here's a table of book items, with titles and authors. You can download it, unzip it, and load it into MySQL.

FULLTEXT search is intended for use with human assistance. It's designed to yield more matches than an ordinary WHERE column LIKE 'text%' filtering operation.

FULLTEXT search is available for MyISAM tables. It is also available for InnoDB tables in MySQL version 5.6.4 or later.

Extract values from JSON type

Mentioned in MySQL 5.7 Reference Manual

  • Multiple matched values by path argument(s)

If it is possible that those arguments could return multiple values, the matched values are autowrapped as an array, in the order corresponding to the paths that produced them. Otherwise, the return value is the single matched value.

  • NULL Result when:
    • any argemunt is NULL
    • path not matched

Returns NULL if any argument is NULL or no paths locate a value in the document.

Regular Expressions

Recover and reset the default root password for MySQL 5.7+

Recovering and resetting the default root password using this method is applicable only for MySQL 5.7+

One to Many

For most cases, working with a 1:M relationship requires us to understand Primary Keys and Foreign Keys.

A Primary key is a column in a table where any single row of that column represents a single entity, or, selecting a value in a primary key column results in exactly one row. Using the above examples, an EMP_ID represents a single employee. If you query for any single EMP_ID, you will see a single row representing the corresponding employee.

A Foreign Key is a column in a table that corresponds to the primary key of another different table. From our example above, the MGR_ID in the EMPLOYEES table is a foreign key. Generally to join two tables, you'll join them based on the primary key of one table and the foreign key in another.

JOINS: Join 3 table with the same name of id.

Server Information

Recover from lost root password