Go to the first, previous, next, last section, table of contents.
This appendix lists some common problems and error messages that MySQL users
have encountered. It describes how to figure out what the causes of problem
are, and what to do to solve them.
When you run into a problem, the first thing you should do is to find out
which program or piece of equipment is causing it:
-
If you have one of the following symptoms, then it is probably a hardware
problems (like memory, motherboard, CPU, or hard disk) or kernel problem:
-
The keyboard doesn't work. This can normally be checked by pressing
Caps Lock. If the Caps Lock light doesn't change you have to replace
your keyboard. (Before doing this, you should try to restart
your computer and check all cables to the keyboard.)
-
The mouse pointer doesn't move.
-
The machine doesn't answer to a remote machine's pings.
-
Other programs that are not related to MySQL don't behave correctly.
-
Your system restarted unexpectedly. (A faulty user level program should
never be able to take down your system.)
In this case you should start by checking all your cables and run some
diagnostic tool to check your hardware!
You should also check whether there are any patches, updates, or service
packs for your operating system that could likely solve your problem.
Check also that all your libraries (like glibc) are up to date.
It's always good to use a machine with ECC memory to discover
memory problems early.
-
If your keyboard is locked up, you may be able to recover by
logging into your machine from another machine and executing
kbd_mode -a.
-
Please examine your system log file (`/var/log/messages' or similar) for
reasons for your problem. If you think the problem is in MySQL,
you should also examine MySQL's log files. See section 5.8 The MySQL Log Files.
-
If you don't think you have hardware problems, you should try to find
out which program is causing problems.
Try using
top, ps, taskmanager, or some similar program,
to check which program is taking all CPU or is locking the machine.
-
Use
top, df, or a similar program to check whether you are out
of memory, disk space, file descriptors, or some other critical resource.
-
If the problem is some runaway process, you can always try to kill it. If it
doesn't want to die, there is probably a bug in the operating system.
If after you have examined all other possibilities and you have
concluded that the MySQL server or a MySQL client
is causing the problem, it's time to create a bug report for our
mailing list or our support team. In the bug report, try to give a
very detailed description of how the system is behaving and what you think is
happening. You should also state why you think that MySQL
is causing the problem. Take into consideration all the situations in
this chapter. State any problems exactly how they appear when you
examine your system. Use the ``copy and paste'' method for any output
and error messages from programs and log files.
Try to describe in detail which program is not working and all
symptoms you see. We have in the past received many bug reports that
state only ``the system doesn't work.'' This doesn't provide us with any
information about what could be the problem.
If a program fails, it's always useful to know the following information:
-
Has the program in question made a segmentation fault (did it dump core)?
-
Is the program taking up all available CPU time? Check with
top. Let
the program run for a while, it may simply be evaluating something
computationally intensive.
-
If the
mysqld server is causing problems, can you get any response
from it with mysqladmin -u root ping or mysqladmin -u root
processlist?
-
What does a client program say when you try to connect to the MySQL server?
(Try with
mysql, for example.) Does the client jam? Do you get any
output from the program?
When sending a bug report, you should follow the outline
described in section 1.7.1.2 Asking Questions or Reporting Bugs.
This section lists some errors that users frequently encounter. You will find
descriptions of the errors, and how to solve the problem here.
See section 5.4.8 Causes of Access denied Errors.
See section 5.4.2 How the Privilege System Works.
This section also covers the related Lost connection to server
during query error.
The most common reason for the MySQL server has gone away error
is that the server timed out and closed the connection. By default, the
server closes the connection after eight hours if nothing has happened. You
can change the time limit by setting the wait_timeout variable when
you start mysqld.
See section 5.2.3 Server System Variables.
If you have a script, you just have to issue the query again for the client
to do an automatic reconnection.
You normally get one of the the following error codes in this case
(which one you get is operating system-dependent):
| Error Code | Description
|
CR_SERVER_GONE_ERROR | The client couldn't send a question to the
server.
|
CR_SERVER_LOST | The client didn't get an error when writing
to the server, but it didn't get a full answer (or any answer) to the question.
|
You will also get an error if someone has killed the running thread with a
KILL statement or a mysqladmin kill command.
Another common reason the MySQL server has gone away error occurs
within an application program is that you tried to run a query after
closing the connection to the server. This indicates a logic error in the
application that should be corrected.
You can check whether the MySQL server died and restarted by executing
mysqladmin version and examining the uptime. If the problem is that
mysqld crashed, you should concentrate on finding the reason for the
crash. Start by checking whether issuing the query again kills the server
again. See section A.4.1 What to Do if MySQL Keeps Crashing.
You can also get these errors if you send a query to the server that is
incorrect or too large. If mysqld receives a packet that is too large
or out of order, it assumes that something has gone wrong with the client and
closes the connection. If you need big queries (for example, if you are
working with big BLOB columns), you can increase the query limit by
setting the server's max_allowed_packet variable, which has a default
value of 1MB. You may also need to increase the maximum packet size on the
client end. More information on setting the packet size is given in
section A.2.10 Packet too large.
You will also get a lost connection if you are sending a packet 16MB or larger
if your client is older than 4.0.8 and your server is 4.0.8 and above, or
the other way around.
If you want to create a bug report regarding this problem, be sure that
you include the following information:
-
Indicate whether or not the MySQL server died. You can find information
about this in the server error log.
See section A.4.1 What to Do if MySQL Keeps Crashing.
-
If a specific query kills
mysqld and the tables involved were
checked with CHECK TABLE before you ran the query, can you provide a
reproducible test case?
See section D.1.6 Making a Test Case If You Experience Table Corruption.
-
What is the value of the
wait_timeout system variable in the MySQL
server? (mysqladmin variables gives you the value of this variable.)
-
Have you tried to run
mysqld with the --log option to
determine whether the problem query appears in the log?
See section 1.7.1.2 Asking Questions or Reporting Bugs.
A MySQL client on Unix can connect to the mysqld server in two
different ways: By using a Unix socket file to connect through a file in the
filesystem (default `/tmp/mysql.sock') or by using TCP/IP, which
connects through a port number. A Unix socket file connection is faster
than TCP/IP but can be used only when connecting to a server on the same
computer. A Unix socket file is used if you don't specify a hostname or if
you specify the special hostname localhost.
If the mysqld server is running on Windows 9x or Me, you can
connect only via TCP/IP. If the server is running on Windows NT, 2000, or XP and
mysqld is started with the --enable-named-pipe option, you
can also connect with named pipes if you run the client on the same host where
the server is running. The name of the named pipe is MySQL by default.
If you don't give a hostname when connecting to mysqld, a MySQL
client first will try to connect to the named pipe. If that doesn't
work, it will connect to the TCP/IP port. You can force the use of named
pipes on Windows by using . as the hostname.
The error (2002) Can't connect to ... normally means that there is no
MySQL server running on the system or that you are using an incorrect Unix
socket filename or TCP/IP port number when trying to connect to the
mysqld server.
Start by checking whether there is a process named mysqld running on
your server host. (Use ps on Unix or the Task Manager on Windows.) If
there is no mysqld process, you should start one.
See section 2.4.2.3 Starting and Troubleshooting the MySQL Server.
If a mysqld process is running, you can check the server by
trying the following commands. The port number or Unix socket filename
might be different in your setup. host_ip represents the IP number of
the machine where the server is running.
shell> mysqladmin version
shell> mysqladmin variables
shell> mysqladmin -h `hostname` version variables
shell> mysqladmin -h `hostname` --port=3306 version
shell> mysqladmin -h 'host_ip' version
shell> mysqladmin --protocol=socket --socket=/tmp/mysql.sock version
Note the use of backquotes rather than forward quotes with the hostname
command; these cause the output of hostname (that is, the current
hostname) to be substituted into the mysqladmin command.
If you have no hostname command or are running on Windows, you can
manually type the hostname of your machine (without backquotes) following the
-h option.
You can also try -h 127.0.0.1 to connect with TCP/IP to the local host.
Here are some reasons the Can't connect to local MySQL server
error might occur:
If you get the error message Can't connect to MySQL server on
some_host, you can try the following things to find out what the
problem is:
-
Check whether the server is running on that host by executing
telnet
some_host 3306 and pressing Enter a couple of times. (3306 is the default
MySQL port number. Change the value if your server is listening to a different
port.) If there is a MySQL server running and listening to the port, you should
get a response that includes the server's version number. If you get an
error such as telnet: Unable to connect to remote host: Connection
refused, then there is no server running on the given port.
-
If the server is running on the local host, try using
mysqladmin -h
localhost variables to connect using the Unix socket file. Verify the
TCP/IP port number that the server is configured to listen to (it is the
value of the port variable.)
-
Make sure that your
mysqld server was not started with the
--skip-networking option. If it was, you will not be able to connect
to it using TCP/IP.
MySQL 4.1 and up uses an authentication protocal based on a password hashing
algorithm that is incompatible with that used by older clients.
If you upgrade the server to 4.1, attempts to connect to it with an
older client may fail with the following message:
shell> mysql
Client does not support authentication protocol requested
by server; consider upgrading MySQL client
To solve this problem, you should use one of the following approaches:
-
Upgrade all client programs to use a 4.1.1 or newer client library.
-
Use an account that still has a pre-4.1-style password when connecting to
the server with a pre-4.1 client program.
-
Reset the password to pre-4.1 style for each user that needs to use a
pre-4.1 client program. This can be done using the
SET PASSWORD
statement:
mysql> SET PASSWORD FOR
-> 'some_user'@'some_host' = OLD_PASSWORD('mypass');
Alternatively, use UPDATE and FLUSH PRIVILEGES:
mysql> UPDATE mysql.user SET Password = OLD_PASSWORD('mypass')
-> WHERE Host = 'some_host' AND User = 'some_user';
mysql> FLUSH PRIVILEGES;
Substitute the password you want to use for ``mypass'' in the preceding
example. MySQL cannot tell you what the original password was, so you'll
need to pick a new one.
-
Tell the server to use the older password hashing algorithm:
-
Start
mysqld with the --old-passwords option.
-
Assign an old-format password to each account that has had its password
updated to the longer 4.1 format. You can identify these accounts with the
following query:
mysql> SELECT Host, User, Password FROM mysql.user
-> WHERE LENGTH(Password) > 16;
For each such account, use the Host and User values and assign
a password using the OLD_PASSWORD() function and either SET PASSWORD or UPDATE, as described
earlier.
For additional background on password hashing and authentication, see
section 5.4.9 Password Hashing in MySQL 4.1.
MySQL client programs prompt for a password when invoked with a
--password or -p option that has no following password value:
shell> mysql -u user_name -p
Enter password:
On some systems, you may find that your password works when specified in an
option file or on the command line, but not when you enter it interactively
at the Enter password: prompt. This occurs when the library provided
by the system to read passwords limits password values to a small number of
characters (typically eight). To work around this, change your password to
a value that is eight or fewer characters long.
If you get the following error, it means that mysqld has received many
connect requests from the host 'host_name' that have been
interrupted in the middle:
Host 'host_name' is blocked because of many connection errors.
Unblock with 'mysqladmin flush-hosts'
The number of interrupted connect requests allowed is determined by the
value of the max_connect_errors system variable. After
max_connect_errors failed requests, mysqld assumes that
something is wrong (for example, that someone is trying to break in), and
blocks the host from further connections until you execute a
mysqladmin flush-hosts command or issue a FLUSH HOSTS
statement.
See section 5.2.3 Server System Variables.
By default, mysqld blocks a host after 10 connection errors.
You can adjust the value by starting the server like this:
shell> mysqld_safe --max_connect_errors=10000 &
Note that if you get this error message for a given host, you should first
verify that there isn't anything wrong with TCP/IP connections from that
host. If you are having network problems, it won't do you any good to
increase the value of the max_connect_errors variable.
If you get a Too many connections error when you try to connect to
the mysqld server, this means that there are already
max_connections clients connected to it.
If you need to support more than the default maximum number of connections
(100), you should restart mysqld with a bigger value for the
max_connections variable.
Note that mysqld actually allows max_connections+1 clients to
connect. The extra connection is reserved for use by accounts that have the
SUPER privilege. By granting the SUPER privilege to
administrators and not to normal users (who should not need it), an
administrator can connect to the server and use SHOW PROCESSLIST to
diagnose problems even if the maximum number of clients already are
connected.
See section 14.5.3.15 SHOW PROCESSLIST Syntax.
The maximum number of connections MySQL can support depends on the quality of
the thread library on a given platform. Linux or Solaris should be
able to support 500-1000 simultaneous connections, depending on how much
RAM you have and what your clients are doing.
If you receive the following message when trying to perform a
ROLLBACK, it means that one or more of the tables you used in the
transaction do not support transactions:
Warning: Some non-transactional changed tables couldn't be rolled back
These non-transactional tables will not be affected by the ROLLBACK
statement.
If you were not deliberately mixing transactional and non-transactional
tables within the transaction, the most likely cause for this message is
that a table you thought was transactional actually is not. This can happen
if you try to create a table using a transactional storage engine that is
not supported by your mysqld server (or that was disabled with a
startup option). If mysqld doesn't support a storage engine, it will
instead create the table as a MyISAM table, which is
non-transactional.
You can check the table type for a table by using either of these statements:
SHOW TABLE STATUS LIKE 'tbl_name';
SHOW CREATE TABLE tbl_name;
See section 14.5.3.17 SHOW TABLE STATUS Syntax and
section 14.5.3.6 SHOW CREATE TABLE Syntax.
You can check the storage engines that your mysqld server supports by
using this statement:
SHOW ENGINES;
Before MySQL 4.1.2, use the following statement instead and check the value
of the variable that is associated with the storage engine in which you are
interested:
SHOW VARIABLES LIKE 'have_%';
For example, to determine whether the InnoDB storage engine is
available, check the value of the have_innodb variable.
See section 14.5.3.8 SHOW ENGINES Syntax and
section 14.5.3.19 SHOW VARIABLES Syntax.
If you issue a query using the mysql client program and receive an
error like the following one, it means that mysql does not
have enough memory to store the entire query result:
mysql: Out of memory at line 42, 'malloc.c'
mysql: needed 8136 byte (8k), memory in use: 12481367 bytes (12189k)
ERROR 2008: MySQL client ran out of memory
To remedy the problem, first check whether your query is correct. Is it
reasonable that it should return so many rows? If not, correct the query and
try again. Otherwise, you can invoke mysql with the --quick
option. This causes it to use the mysql_use_result() to retrieve the
result set, which places less of a load on the client (but more on the
server).
A communication packet is a single SQL statement sent to the MySQL server
or a single row that is sent to the client.
In MySQL 3.23, the largest possible packet is 16MB, due to limits in the
client/server protocol. In MySQL 4.0.1 and up, the limit is 1GB.
When a MySQL client or the mysqld server receives a packet bigger
than max_allowed_packet bytes, it issues a Packet too
large error and closes the connection. With some clients, you may also
get a Lost connection to MySQL server during query error if the
communication packet is too large.
Note that the client and the server each has its own
max_allowed_packet variable. If you want to handle big packets,
you have to increase this variable both in the client and in the server.
If you are using the mysql client program, its default
max_allowed_packet variable is 16MB. That is also the maximum value
before MySQL 4.0. To set a larger value from 4.0 on, start mysql like
this:
mysql> mysql --max_allowed_packet=32M
That sets the packet size to 32MB.
The sever's default max_allowed_packet value is 1MB. You can increase
this if the server needs to handle big queries (for example, if you are
working with big BLOB columns). For example, to set the variable to
16MB, start the server like this:
mysql> mysqld --max_allowed_packet=16M
Before MySQL 4.0, use this syntax instead:
mysql> mysqld --set-variable=max_allowed_packet=16M
You can also use an option file to set max_allowed_packet. For
example, to set the size for the server to 16MB, add the following lines in
an option file:
[mysqld]
max_allowed_packet=16M
Before MySQL 4.0, use this syntax instead:
[mysqld]
set-variable = max_allowed_packet=16M
It's safe to increase the value of this variable because the extra memory is
allocated only when needed. For example, mysqld allocates more
memory only when you issue a long query or when mysqld must return a
large result row. The small default value of the variable is more a
precaution to catch incorrect packets between the client and server and also
to ensure that you don't run out of memory by using large packets
accidentally.
You can also get strange problems with large packets if you are using large
BLOB values but have not given mysqld access to enough memory
to handle the query. If you suspect this is the case, try adding
ulimit -d 256000 to the beginning of the mysqld_safe script
and restart mysqld.
The server error log can be a useful source of information about connection
problems.
See section 5.8.1 The Error Log.
Starting with MySQL 3.23.40, if you start the server with the
--warnings option (or --log-warnings from MySQL 4.0.3 on), you
might find messages like this in your error log:
010301 14:38:23 Aborted connection 854 to db: 'users' user: 'josh'
If Aborted connections messages appear in the error log, the cause
can be any of the following:
-
The client program did not call
mysql_close() before exiting.
-
The client had been sleeping more than
wait_timeout or
interactive_timeout seconds without issing any requests to the server.
See section 5.2.3 Server System Variables.
-
The client program ended abruptly in the middle of a data transfer.
When any of these things happen, the server increments the
Aborted_clients status variable.
The server increments the Aborted_connects status variable when the
following things happen:
-
A client didn't have privileges to connect to a database.
-
A client uses a wrong password.
-
A connection packet doesn't contain the right information.
-
It takes more than
connect_timeout seconds to get
a connect packet.
See section 5.2.3 Server System Variables.
Note that if these kinds of things happen, it might indicate that someone is
trying to break into your database!
Other reasons for problems with aborted clients or aborted connections:
-
Use of Ethernet protocol with Linux, both half and full duplex.
Many Linux Ethernet drivers have this bug. You should test for this
bug by transferring a huge file via FTP between the client and server machines.
If a transfer goes in burst-pause-burst-pause ... mode, you are
experiencing a Linux duplex syndrome.
The only solution is switching the duplex mode for both your network card
and Hub/Switch to either full duplex or to half duplex and testing the
results to determine the best setting.
-
Some problem with the thread library that causes interrupts on reads.
-
Badly configured TCP/IP.
-
Faulty Ethernets, hubs, switches, cables, and so forth. This can be diagnosed
properly only by replacing hardware.
-
The
max_allowed_packet variable value is too small or queries require
more memory than you have allocated for mysqld.
See section A.2.10 Packet too large.
There are several ways a full-table error can occur:
If you get an error for some queries of the following type, it means
that MySQL can't create a temporary file for the result set in the
temporary directory:
Can't create/write to file '\\sqla3fe_0.ism'.
The preceding error is a
typical error message for Windows; the Unix error message is similar.
The fix is to start mysqld with the --tmpdir option or to
add the option to the [mysqld] section of your option file.
For example, to specify a directory of `C:\temp', use these lines:
[mysqld]
tmpdir=C:/temp
The `C:\temp' directory must already exist. See section 4.3.2 Using Option Files.
Check also the error code that you get with perror. One reason
the server cannot write to a table is that the filesystem is full:
shell> perror 28
Error code 28: No space left on device
If you get Commands out of sync; you can't run this command now
in your client code, you are calling client functions in the wrong order.
This can happen, for example, if you are using mysql_use_result() and
try to execute a new query before you have called mysql_free_result().
It can also happen if you try to execute two queries that return data without
calling mysql_use_result() or mysql_store_result() in between.
If you get the following error, it means that when mysqld was started
or when it reloaded the grant tables, it found an account in the user
table that had an invalid password.
Found wrong password for user: 'some_user'@'some_host'; ignoring user
As a result, the account is simply ignored by the permission system.
The following list indicates possible causes of and fixes for this problem:
If you get either of the following errors, it usually means that no table
exists in the current database with the name xxx:
Table 'xxx' doesn't exist
Can't find file: 'xxx' (errno: 2)
In some cases, it may be that the table does exist but that you are not
referring to it correctly:
-
Because MySQL uses directories and files to store databases and
tables, database and table names are case sensitive if they are located on
a filesystem that has case-sensitive filenames.
-
Even for filesystems that are not case sensitive, such as on Windows, all
references to a given table within a query must use the same lettercase.
You can check which tables you have in the current database with
SHOW TABLES. See section 14.5.3 SET and SHOW Syntax.
You might see an error like this if you have character set problems:
MySQL Connection Failed: Can't initialize character set xxx
This error can have any of the following causes:
-
The character set is a multi-byte character set and you have no support
for the character set in the client.
In this case, you need to recompile the client by running
configure
with the --with-charset=xxx or --with-extra-charsets=xxx
option.
See section 2.3.2 Typical configure Options.
All standard MySQL binaries are compiled with
--with-extra-character-sets=complex, which enables support for
all multi-byte character sets. See section 5.7.1 The Character Set Used for Data and Sorting.
-
The character set is a simple character set that is not compiled into
mysqld, and the character set definition files are not in the place
where the client expects to find them.
In this case, you need to use one of the following methods to solve the problem:
-
Recompile the client with support for the character set.
See section 2.3.2 Typical
configure Options.
-
Specify to the client the directory where the character set definition files
are located. For many clients, you can do this with the
--character-sets-dir option.
-
Copy the character definition files to the path where the client expects them
to be.
If you get ERROR '...' not found (errno: 23), Can't open file:
... (errno: 24), or any other error with errno 23 or errno 24
from MySQL, it means that you haven't allocated enough file descriptors for
the MySQL server. You can use the perror utility to get a
description of what the error number means:
shell> perror 23
File table overflow
shell> perror 24
Too many open files
shell> perror 11
Resource temporarily unavailable
The problem here is that mysqld is trying to keep open too many
files simultaneously. You can either tell mysqld not to open so
many files at once or increase the number of file descriptors
available to mysqld.
To tell mysqld to keep open fewer files at a time, you can make the
table cache smaller by reducing the value of the table_cache system
variable (the default value is 64). Reducing the value of
max_connections also will reduce the number of open files (the
default value is 100).
To change the number of file descriptors available to mysqld, you can
use the --open-files-limit option to mysqld_safe or (as of
MySQL 3.23.30) set the the open_files_limit system variable.
See section 5.2.3 Server System Variables.
The easiest way to set these values is to add an option to your option file.
See section 4.3.2 Using Option Files. If you have an old version of mysqld that
doesn't support setting the open files limit, you can edit the
mysqld_safe script. There is a commented-out line ulimit -n
256 in the script. You can remove the `#' character to uncomment
this line, and change the number 256 to affect the number of file
descriptors available to mysqld.
--open-files-limit and ulimit can increase the number of file
descriptors, but only up to the limit imposed by the operating system. There
is also a ``hard'' limit that can only be overridden if you start
mysqld_safe or mysqld as root (just remember that you
also need to start the server with the --user option in this case).
If you need to increase the operating system limit on the number of file
descriptors available to each process, consult the documentation for your
system.
Note: If you run the tcsh shell, ulimit will not work!
tcsh will also report incorrect values when you ask for the current
limits. In this case, you should start mysqld_safe using sh.
When you are linking an application program to use the MySQL client library,
you might get undefined reference errors for symbols that start with mysql_,
such as those shown here:
/tmp/ccFKsdPa.o: In function `main':
/tmp/ccFKsdPa.o(.text+0xb): undefined reference to `mysql_init'
/tmp/ccFKsdPa.o(.text+0x31): undefined reference to `mysql_real_connect'
/tmp/ccFKsdPa.o(.text+0x57): undefined reference to `mysql_real_connect'
/tmp/ccFKsdPa.o(.text+0x69): undefined reference to `mysql_error'
/tmp/ccFKsdPa.o(.text+0x9a): undefined reference to `mysql_close'
You should be able to solve this problem by adding -Ldir_path
-lmysqlclient at the end of your link command, where dir_path
represents the pathname of the directory where the client library is
located. To find the correct directory, try this command:
shell> mysql_config --libs
The command output might indicate other libraries that should be specified
on the link command as well.
If you get undefined reference errors for the uncompress
or compress functions, add -lz to the end of your
link command and try again.
If you get undefined reference errors for functions that should
exist on your system, such as connect, check the manual page for the
function in question to determine which libraries you should add to the link
command.
You might get undefined reference errors such as the following for
functions that don't exist on your system:
mf_format.o(.text+0x201): undefined reference to `__lxstat'
This usually means that your MySQL client library was compiled on a system
that is not 100% compatible with yours. In this case, you should download
the latest MySQL source distribution and compile MySQL yourself.
See section 2.3 MySQL Installation Using a Source Distribution.
You might get undefined reference errors at runtime when you try to execute
a MySQL program. If these errors indicate symbols that start with
mysql_ or that the mysqlclient library can't be found, it
means that your system can't find the shared `libmysqlclient.so' library.
The fix for this is to tell your system to search for shared
libraries where the library is located. Use whichever of the following methods
is appropriate for your system:
-
Add the path to the directory where `libmysqlclient.so' is located to the
LD_LIBRARY_PATH environment variable.
-
Add the path to the directory where `libmysqlclient.so' is located to the
LD_LIBRARY environment variable.
-
Copy `libmysqlclient.so' to some directory that is searched by your system,
such as `/lib', and update the shared library information by executing
ldconfig.
Another way to solve this problem is by linking your program statically with
the -static option, or by removing the dynamic MySQL libraries
before linking your code. Before trying the second method, you should be
sure that no other programs are using the dynamic libraries.
On Windows, you can run the server as a Windows service using normal user
accounts beginning with MySQL 4.0.17 and 4.1.2. (Older MySQL versions
required you to have administrator rights. This was a bug introduced in
MySQL 3.23.54).
On Unix, the MySQL server mysqld can be started and run by any user.
However, you should avoid running the server as the Unix root user
for security reasons. In order to change mysqld to run as a normal
unprivileged Unix user user_name, you must do the following:
-
Stop the server if it's running (use
mysqladmin shutdown).
-
Change the database directories and files so that
user_name has
privileges to read and write files in them (you might need to do this as
the Unix root user):
shell> chown -R user_name /path/to/mysql/datadir
If directories or files within the MySQL data directory are symbolic links,
you'll also need to follow those links and change the directories and files
they point to. chown -R might not follow symbolic links for you.
-
Start the server as user
user_name. If you are using MySQL 3.22 or
later, another alternative is to start mysqld as the Unix root
user and use the --user=user_name option. mysqld will switch
to run as the Unix user user_name before accepting any connections.
-
To start the server as the given user automatically at system
startup time, specify the username by adding a
user option to
the [mysqld] group of the `/etc/my.cnf' option file or the
`my.cnf' option file in the server's data directory. For example:
[mysqld]
user=user_name
At this point, your mysqld process should be running as
the Unix user user_name. One thing hasn't changed, though: the
contents of the grant table in the mysql database. By default, the
grant tables are initialized such that only the MySQL
root accounts have permission to access the mysql
database or to create or drop databases. Unless you have changed those
permissions, they still hold. This does not stop you from accessing
MySQL as the MySQL root user when you're logged in
as a Unix user other than root; just start your
client programs with the --user=root option.
Note that accessing the MySQL server as the MySQL root user from
a client program by supplying --user=root on the command line has
nothing to do with MySQL running as the Unix root user, or,
indeed, as any other Unix user. The access permissions and usernames of MySQL
accounts are completely separate from those of Unix login accounts. The only
connection with Unix usernames is that if you don't provide a --user
option when you invoke a client program, the client will try to connect
using your Unix login name as your MySQL username.
If your Unix machine itself isn't secured, you should assign passwords
to the MySQL root accounts in the grant tables. Otherwise, any
user with a login account on that machine can run mysql with a
--user=root option and perform any operation. (It is a good idea to
assign passwords to MySQL accounts in any case, but especially so when
other login accounts exist on the server host.
See section 2.4 Post-installation Setup and Testing.
If you have problems with file permissions, the UMASK environment
variable might be set incorrectly when mysqld starts. For example,
MySQL might issue the following error message when you create a table:
ERROR: Can't find file: 'path/with/filename.frm' (Errcode: 13)
The default umask value is 0660. You can change this behavior by
starting mysqld_safe as follows:
shell> UMASK=384 # = 600 in octal
shell> export UMASK
shell> /path/to/mysqld_safe &
By default, MySQL creates database and RAID directories
with an access permission value of 0700. You can modify this
behavior by setting the UMASK_DIR variable. If you set its value, new
directories are created with the combined UMASK and UMASK_DIR
values. For example, if you want to give group access to all new
directories, you can do this:
shell> UMASK_DIR=504 # = 770 in octal
shell> export UMASK_DIR
shell> /path/to/mysqld_safe &
In MySQL 3.23.25 and above, MySQL assumes that the
value for UMASK and UMASK_DIR is in octal if it starts
with a zero.
See section E Environment Variables.
All MySQL versions are tested on many platforms before they are
released. This doesn't mean that there are no bugs in
MySQL, but if there are bugs, they should be very few and can be
hard to find. If you have a problem, it will always help if you try to
find out exactly what crashes your system, as you will have a much better
chance of getting the problem fixed quickly.
First, you should try to find out whether the problem is that the mysqld server dies or whether your problem has to do with your
client. You can check how long your mysqld server has been up by
executing mysqladmin version. If mysqld has died and
restarted, you may find the reason by looking in the server's error log.
See section 5.8.1 The Error Log.
On some systems you can find in the error log a stack trace of where
mysqld died that you can resolve with the resolve_stack_dump
program. See section D.1.4 Using a Stack Trace. Note that the variable values written in
the error log may not always be 100% correct.
Many server crashes are caused by corrupted datafiles or index files. MySQL
will update the files on disk with the write() system call after every
SQL statement and before the client is notified about the result. (This is
not true if you are running with delay_key_write, in which case the
data is written but not the indexes.) This means that the data is safe even
if mysqld crashes, because the operating system will ensure that the
unflushed data is written to disk. You can force MySQL to flush everything
to disk after every SQL statement by starting mysqld with the
--flush option.
The preceding means that normally you should not get corrupted tables unless
one of the following happens:
-
The MySQL server or the server host was killed in the middle of an update.
-
You have found a bug in
mysqld that caused it to die in the
middle of an update.
-
Some external program is manipulating datafiles or index files at the same
time as
mysqld without locking the table properly.
-
You are running many
mysqld servers using the same data directory on
a system that doesn't support good filesystem locks (normally handled by the
lockd lock manager), or you are running multiple servers with the
--skip-external-locking option.
-
You have a crashed datafile or index file that contains very corrupt data that
made
mysqld confused.
-
You have found a bug in the data storage code. This isn't likely, but it's
at least possible. In this case, you can try to change the table type to
another storage engine by using
ALTER TABLE on a repaired copy of the
table.
Because it is very difficult to know why something is crashing, first try to
check whether things that work for others crash for you. Please try
the following things:
-
Stop the
mysqld server with mysqladmin shutdown, run
myisamchk --silent --force */*.MYI from the data directory to check
all MyISAM tables, and restart mysqld. This will ensure that
you are running from a clean state.
See section 5 Database Administration.
-
Start
mysqld with the --log option and try to determine
from the information written to the log whether some specific query kills
the server. About 95% of all bugs are related to a particular query.
Normally, this will be one of the last queries in the log file just before
the server restarts.
See section 5.8.2 The General Query Log.
If you can repeatedly kill MySQL with a specific query, even
when you have checked all tables just before issuing it, then you
have been able to locate the bug and should submit a bug report for it.
See section 1.7.1.3 How to Report Bugs or Problems.
-
Try to make a test case that we can use to repeat the problem.
See section D.1.6 Making a Test Case If You Experience Table Corruption.
-
Try running the tests in the `mysql-test' directory and the MySQL
benchmarks. See section 22.1.2 MySQL Test Suite. They should test MySQL
rather well. You can also add code to the benchmarks that simulates
your application. The benchmarks can be found in the `bench'
directory in the source distribution or, for a binary distribution, in
the `sql-bench' directory under your MySQL installation
directory.
-
Try the
fork_big.pl script. (It is located in the `tests'
directory of source distributions.)
-
If you configure MySQL for debugging, it will be much easier to
gather information about possible errors if something goes wrong.
Configuring MySQL for debugging causes a safe memory allocator to be
included that can find some errors. It also provides a lot of output
about what is happening. Reconfigure MySQL with the
--with-debug
or --with-debug=full option to configure and then recompile.
See section D.1 Debugging a MySQL server.
-
Have you applied the latest patches for your operating system?
-
Use the
--skip-external-locking option to mysqld. On some
systems, the lockd lock manager does not work properly; the
--skip-external-locking option tells mysqld not to use external
locking. (This means that you cannot run two mysqld servers on the same
data directory and that you must be careful if you use myisamchk.
Nevertheless, it may be instructive to try the option as a test.)
-
Have you tried
mysqladmin -u root processlist when mysqld
appears to be running but not responding? Sometimes mysqld is not
comatose even though you might think so. The problem may be that all
connections are in use, or there may be some internal lock problem.
mysqladmin -u root processlist usually will be able to make a
connection even in these cases, and can provide useful information about the
current number of connections and their status.
-
Run the command
mysqladmin -i 5 status or mysqladmin -i 5
-r status in a separate window to produce statistics while you run
your other queries.
-
Try the following:
-
Start
mysqld from gdb (or another debugger).
See section D.1.3 Debugging mysqld under gdb.
-
Run your test scripts.
-
Print the backtrace and the local variables at the 3 lowest levels. In
gdb you can do this with the following commands when mysqld
has crashed inside gdb:
backtrace
info local
up
info local
up
info local
With gdb, you can also examine which threads exist with info
threads and switch to a specific thread with thread #, where
# is the thread ID.
-
Try to simulate your application with a Perl script to force
MySQL to crash or misbehave.
-
Send a normal bug report. See section 1.7.1.3 How to Report Bugs or Problems. Be even more detailed
than usual. Because MySQL works for many people, it may be that the
crash results from something that exists only on your computer (for example,
an error that is related to your particular system libraries).
-
If you have a problem with tables containing dynamic-length rows and you are
using only
VARCHAR columns (not BLOB or TEXT columns), you
can try to change all VARCHAR to CHAR with ALTER
TABLE. This will force MySQL to use fixed-size rows.
Fixed-size rows take a little extra space, but are much more tolerant to
corruption.
The current dynamic row code has been in use at MySQL AB for several years
with very few problems, but by nature dynamic-length rows are more prone to
errors, so it may be a good idea to try this strategy to see whether it helps.
If you have never set a root password for MySQL, the server will
not require a password at all for connecting as root. However, it is
recommended to set a password for each account. See section 5.3.1 General Security Guidelines.
If you set a root password previously, but have forgotten what it
was, you can set a new password. The following procedure is for Windows
systems. The procedure for Unix systems is given later in this section.
The procedure under Windows:
-
Log onto your system as Administrator.
-
Stop the MySQL server if it is running. For a server that is running as a
Windows service, go to the Services manager:
Start Menu -> Control Panel -> Administrative Tools -> Services
Then find the MySQL service in the list, and stop it.
If your server is not running as a service, you may need to use the Task
Manager to force it to stop.
-
Open a console window to get to the DOS command prompt:
Start Menu -> Run -> cmd
-
We are assuming you installed MySQL to `C:\mysql'. If you installed
MySQL to another location, adjust the following commands accordingly.
At the DOS command prompt, execute this command:
C:\> C:\mysql\bin\mysqld-nt --skip-grant-tables
This starts the server in a special mode that does not check the grant
tables to control access.
-
Keeping the first console window open, open a second console window and
execute the following commands (type each on a single line):
C:\> C:\mysql\bin\mysqladmin -u root
flush-privileges password "newpwd"
C:\> C:\mysql\bin\mysqladmin -u root -p shutdown
Replace ``newpwd'' with the actual root password that you want
to use.
The second command will prompt you to enter the new password for access.
Enter the password that you assigned in the first command.
-
Now you can start the MySQL server in normal mode again. If you run the
server as a service, start it from the Windows Services window. If you
start the server manually, use whatever command you normally use.
In a Unix environment, the procedure is as follows:
-
Log onto your system as either the Unix
root user or as the
same user that the mysqld server runs as.
-
Locate the `.pid' file that contains the server's process ID.
The exact location and name of this file depends on your distribution,
hostname, and configuration. Common locations are: `/var/lib/mysql/',
`/var/run/mysqld/' and `/usr/local/mysql/data/'. Generally, the
filename has the extension of `.pid' and begins with either
`mysqld' or your system's hostname.
Now you can stop the MySQL server by sending a normal
kill
(not kill -9) to the mysqld process, using the name of the
`.pid' file in the following command:
shell> kill `cat /mysql-data-directory/hostname.pid`
Note the use of backquotes rather than forward quotes with the cat
command; these cause the output of cat
to be substituted into the kill command.
-
Restart the MySQL server with the special
--skip-grant-tables option:
shell> mysqld_safe --skip-grant-tables &
-
Set a new password for the
root@localhost MySQL account:
shell> mysqladmin -u root flush-privileges password "newpwd"
Replace ``newpwd'' with the actual root password that you want
to use.
-
You should now be able to connect using the new password.
Alternatively, you can set the new password using the mysql client:
-
Stop
mysqld and restart it with the --skip-grant-tables
option as described earlier.
-
Connect to the
mysqld server with this command:
shell> mysql -u root
-
Issue the following statements in the
mysql client:
mysql> UPDATE mysql.user SET Password=PASSWORD('newpwd')
-> WHERE User='root';
mysql> FLUSH PRIVILEGES;
Replace ``newpwd'' with the actual root password that you want
to use.
-
You should now be able to connect using the new password.
When a disk-full condition occurs, MySQL does the following:
-
It checks once every minute to see whether there is enough space to
write the current row. If there is enough space, it continues as if nothing had
happened.
-
Every six minutes it writes an entry to the log file warning about the
disk-full condition.
To alleviate the problem, you can take the following actions:
-
To continue, you only have to free enough disk space to insert all records.
-
To abort the thread, you must send a
mysqladmin kill to the thread.
The thread will be aborted the next time it checks the disk (in one minute).
-
Note that other threads may be waiting for the table that caused the disk
full condition. If you have several ``locked'' threads, killing the one
thread that is waiting on the disk-full condition will allow the other
threads to continue.
Exceptions to the preceding behavior are when you use REPAIR TABLE or
OPTIMIZE TABLE or when the indexes are created in a batch after
LOAD DATA INFILE or after an ALTER TABLE statement.
All of these statements may create large temporary files that left to
themselves would cause big problems for the rest of the system. If the disk
becomes full while MySQL is doing any of these operations,
it will remove the big temporary files and mark the table as crashed.
The exception is that for ALTER TABLE, the old table will be left
unchanged.
MySQL uses the value of the TMPDIR environment variable as the
pathname of the directory in which to store temporary files. If you don't
have TMPDIR set, MySQL uses the system default, which is normally
`/tmp', `/var/tmp', or `/usr/tmp'. If the filesystem
containing your temporary file directory is too small, you can use the
--tmpdir option to mysqld to specify a directory in a
filesystem where you have enough space.
Starting from MySQL 4.1, the --tmpdir option can be set to a list
of several paths that are used in round-robin fashion. Paths should be
separated by colon characters (`:') on Unix and semicolon characters
(`;') on Windows, NetWare, and OS/2. Note: To spread load
between several physical disks, these paths should end up on different
physical disks, not different partitions of the same disk.
If the MySQL server is acting as a replication slave, you should not set
--tmpdir to point to a directory on a memory-based filesystem or to a
directory that is cleared when the server host restarts. A replication
slave needs some of its temporary files to survive a machine restart so that
it can replicate temporary tables or LOAD DATA INFILE operations. If
files in the temporary file directory are lost when the server restarts,
replication will fail.
MySQL creates all temporary files as hidden files. This ensures
that the temporary files will be removed if mysqld is terminated. The
disadvantage of using hidden files is that you will not see a big temporary
file that fills up the filesystem in which the temporary file directory is
located.
When sorting (ORDER BY or GROUP BY), MySQL normally
uses one or two temporary files. The maximum disk space required is determined
by the following expression:
(length of what is sorted + sizeof(row pointer))
* number of matched rows
* 2
The row pointer size is usually four bytes, but may grow in the future for
really big tables.
For some SELECT queries, MySQL also creates temporary SQL
tables. These are not hidden and have names of the form `SQL_*'.
ALTER TABLE creates a temporary table in the same directory as
the original table.
The default location for the Unix socket file that the server uses for
communication with local clients is `/tmp/mysql.sock'. This might
cause problems, because on some versions of Unix, anyone can delete files
in the `/tmp' directory.
On most versions of Unix, you can protect your `/tmp' directory so that
files can be deleted only by their owners or the superuser (root).
To do this, set the sticky bit on the `/tmp' directory by
logging in as root and using the following command:
shell> chmod +t /tmp
You can check whether the sticky bit is set by executing ls -ld
/tmp. If the last permission character is t, the bit is set.
Another approach is to change the place where the server creates the Unix
socket file. If you do this, you should also let client programs know the
new location of the file. You can specify the file location in several
ways:
You can test whether the new socket location works by attempting to connect to
the server with this command:
shell> mysqladmin --socket=/path/to/socket version
If you have a problem with SELECT NOW() returning values in GMT and
not your local time, you have to tell the server your current time zone.
The same applies if UNIX_TIMESTAMP() returns the wrong value.
This should be done for the environment in which the server runs, for
example, in mysqld_safe or mysql.server.
See section E Environment Variables.
You can set the time zone for the server with the
--timezone=timezone_name option to mysqld_safe. You can
also set it by setting the TZ environment variable before you
start mysqld.
The allowable values for --timezone or TZ are
system-dependent. Consult your operating system documentation to see
what values are acceptable.
By default, MySQL searches are not case sensitive (although there are
some character sets that are never case-insensitive, such as czech).
This means that if you search with col_name LIKE 'a%', you will get all
column values that start with A or a. If you want to make this
search case sensitive, make sure that one of the operands is a binary string.
You can do this with the BINARY operator. Write the condition as either
BINARY col_name LIKE 'a%' or col_name LIKE BINARY 'a%'.
If you want a column always to be treated in case-sensitive fashion,
declare it as BINARY. See section 14.2.5 CREATE TABLE Syntax.
Simple comparison operations (>=, >, = , < , <=, sorting and grouping)
are based on each character's ``sort value''. Characters with the same
sort value (such as `E', `e' and `é') are treated as the
same character.
If you are using Chinese data in the so-called big5 encoding, you
want to make all character columns BINARY. This works because the
sorting order of big5 encoding characters is based on the order of
ASCII codes. As of MySQL 4.1, you can explicitly declare that a column should
use the big5 character set:
CREATE TABLE t (name CHAR(40) CHARACTER SET big5);
The format of a DATE value is 'YYYY-MM-DD'. According to
standard SQL, no other format is allowed. You should use this format in
UPDATE expressions and in the WHERE clause of SELECT
statements. For example:
mysql> SELECT * FROM tbl_name WHERE date >= '2003-05-05';
As a convenience, MySQL automatically converts a date to a number if
the date is used in a numeric context (and vice versa). It is also smart
enough to allow a ``relaxed'' string form when updating and in a WHERE
clause that compares a date to a TIMESTAMP, DATE, or a
DATETIME column. (Relaxed form means that any punctuation character
may be used as the separator between parts. For example, '2004-08-15'
and '2004#08#15' are equivalent.) MySQL can also convert a
string containing no separators (such as '20040815'), provided it
makes sense as a date.
The special date '0000-00-00' can be stored and retrieved as
'0000-00-00'. When using a '0000-00-00' date through
Connector/ODBC, it is automatically converted to NULL in
Connector/ODBC 2.50.12 and above, because ODBC can't handle this kind of
date.
Because MySQL performs the conversions described above, the following
statements work:
mysql> INSERT INTO tbl_name (idate) VALUES (19970505);
mysql> INSERT INTO tbl_name (idate) VALUES ('19970505');
mysql> INSERT INTO tbl_name (idate) VALUES ('97-05-05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997.05.05');
mysql> INSERT INTO tbl_name (idate) VALUES ('1997 05 05');
mysql> INSERT INTO tbl_name (idate) VALUES ('0000-00-00');
mysql> SELECT idate FROM tbl_name WHERE idate >= '1997-05-05';
mysql> SELECT idate FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT MOD(idate,100) FROM tbl_name WHERE idate >= 19970505;
mysql> SELECT idate FROM tbl_name WHERE idate >= '19970505';
However, the following will not work:
mysql> SELECT idate FROM tbl_name WHERE STRCMP(idate,'20030505')=0;
STRCMP() is a string function, so it converts idate to a
string in 'YYYY-MM-DD' format and performs a string comparison.
It does not convert '20030505' to the date '2003-05-05'
and perform a date comparison.
The MySQL server packs dates for storage, so it can't store a given date
if it would not fit onto the result buffer. Note that MySQL does very
limited checking whether the date is correct. If you store an incorrect
date, such as '2004-2-31', MySQL stores it as given. The rules
for accepting a date are:
-
If MySQL can store and retrieve a given date as given, the date is accepted
for
DATE and DATETIME columns even if it is not strictly legal.
-
Day values from 0 to 31 are accepted for any date. This makes it
very convenient for Web applications where you ask year, month and day
in 3 different fields.
-
The day or month value may be zero. This is convenient if you want
to store a birthdate in a
DATE column and you only know part
of the date.
If the date cannot be converted to any reasonable value, a 0 is
stored in the DATE column, which will be retrieved as
'0000-00-00'. This is both a speed and convenience issue. We believe
that the database server's responsibility is to retrieve the same date you
stored (even if the data was not logically correct in all cases). We think
it is up to the application and not the server to check the dates.
The concept of the NULL value is a common source of confusion for
newcomers to SQL, who often think that NULL is the same thing as an
empty string ''. This is not the case. For example, the following
statements are completely different:
mysql> INSERT INTO my_table (phone) VALUES (NULL);
mysql> INSERT INTO my_table (phone) VALUES ('');
Both statements insert a value into the phone column, but the first
inserts a NULL value and the second inserts an empty string. The
meaning of the first can be regarded as ``phone number is not known'' and the
meaning of the second can be regarded as ``the person is known to have no
phone, and thus no phone number.''
To help with NULL handling, you can use the IS NULL and
IS NOT NULL operators and the IFNULL() function.
In SQL, the NULL value is never true in comparison to any
other value, even NULL. An expression that contains NULL
always produces a NULL value unless otherwise indicated in
the documentation for the operators and functions involved in the
expression. All columns in the following example return NULL:
mysql> SELECT NULL, 1+NULL, CONCAT('Invisible',NULL);
If you want to search for column values that are NULL, you
cannot use the =NULL test. The following statement returns no
rows, because expr = NULL is never true for any expression:
mysql> SELECT * FROM my_table WHERE phone = NULL;
To look for NULL values, you must use the IS NULL test.
The following statements showhow to find the NULL phone number and the
empty phone number:
mysql> SELECT * FROM my_table WHERE phone IS NULL;
mysql> SELECT * FROM my_table WHERE phone = '';
You can add an index on a column that can have NULL
values only if you are using MySQL 3.23.2 or newer and are using the
MyISAM, InnoDB, or BDB storage engine.
In earlier versions and with other storage engines, you must declare indexed
columns NOT NULL. This also means you cannot then insert
NULL into an indexed column.
When reading data with LOAD DATA INFILE, empty or missing columns
are updated with ''. If you want a NULL value in a column,
you should use \N in the data file. The literal word 'NULL'
may also be used under some circumstances.
See section 14.1.5 LOAD DATA INFILE Syntax.
When using DISTINCT, GROUP BY, or ORDER BY, all
NULL values are regarded as equal.
When using ORDER BY, NULL values are presented first, or
last if you specify DESC to sort in descending order. Exception:
In MySQL 4.0.2 through 4.0.10, NULL values sort first
regardless of sort order.
Aggregate (summary) functions such as COUNT(), MIN(), and
SUM() ignore NULL values. The exception to this is
COUNT(*), which counts rows and not individual column values.
For example, the following statement produces two counts.
The first is a count of the number of rows in the table, and the second
is a count of the number of non-NULL values in the age
column:
mysql> SELECT COUNT(*), COUNT(age) FROM person;
For some column types, MySQL handles NULL values specially. If you
insert NULL into a TIMESTAMP column, the
current date and time is inserted. If you insert NULL into an
AUTO_INCREMENT column, the next number in the sequence is inserted.
You can use an alias to refer to a column in GROUP BY,
ORDER BY, or HAVING clauses. Aliases can also be used
to give columns better names:
SELECT SQRT(a*b) AS rt FROM tbl_name GROUP BY rt HAVING rt > 0;
SELECT id, COUNT(*) AS cnt FROM tbl_name GROUP BY id HAVING cnt > 0;
SELECT id AS 'Customer identity' FROM tbl_name;
Note that standard SQL doesn't allow you to refer to a column alias in a
WHERE clause. This is because when the WHERE code is
executed, the column value may not yet be determined. For example, the
following query is illegal:
SELECT id, COUNT(*) AS cnt FROM tbl_name WHERE cnt > 0 GROUP BY id;
The WHERE statement is executed to determine which rows should
be included in the GROUP BY part, whereas HAVING is used to
decide which rows from the result set should be used.
MySQL does not support subqueries prior to Version 4.1, or the use of more
than one table in the DELETE statement prior to Version 4.0. If your
version of MySQL does not support subqueries or multiple-table DELETE
statements, you can use the following approach to delete rows from two
related tables:
-
SELECT the rows based on some WHERE condition in the main table.
-
DELETE the rows in the main table based on the same condition.
-
DELETE FROM related_table WHERE related_column IN (selected_rows).
If the total length of the DELETE statement for related_table is
more than 1MB (the default value of the max_allowed_packet system
variable), you should split it into smaller parts and execute multiple
DELETE statements. You will probably get the fastest DELETE
by specifying only 100 to 1000 related_column values per statement if the
related_column is indexed. If the related_column isn't
indexed, the speed is independent of the number of arguments in the
IN clause.
If you have a complicated query that uses many tables but that doesn't
return any rows, you should use the following procedure to find out what
is wrong:
-
Test the query with
EXPLAIN to check whether you can find something
that is obviously wrong.
See section 7.2.1 EXPLAIN Syntax (Get Information About a SELECT).
-
Select only those columns that are used in the
WHERE clause.
-
Remove one table at a time from the query until it returns some rows.
If the tables are large, it's a good idea to use
LIMIT 10 with the query.
-
Issue a
SELECT for the column that should have matched a row against
the table that was last removed from the query.
-
If you are comparing
FLOAT or DOUBLE columns with numbers that
have decimals, you can't use equality (=) comparisons. This problem
is common in most computer languages because not all floating-point values
can be stored with exact precision. In some cases, changing the
FLOAT to a DOUBLE will fix this.
See section A.5.7 Problems with Floating-point Comparisons.
-
If you still can't figure out what's wrong, create a minimal test that can
be run with
mysql test < query.sql that shows your problems. You can
create a test file by dumping the tables with mysqldump --quick
db_name tbl_name_1 ... tbl_name_n > query.sql. Open the file in an editor,
remove some insert lines (if there are too many of them), and add your
SELECT statement at the end of the file.
Verify that the test file demonstrates your problem by executing these
commands:
shell> mysqladmin create test2
shell> mysql test2 < query.sql
Post the test file using mysqlbug to the general MySQL mailing list.
See section 1.7.1.1 The MySQL Mailing Lists.
Floating-point numbers sometimes cause confusion because they
are not stored as exact values inside computer architecture. What you
can see on the screen usually is not the exact value of the number.
The column types FLOAT, DOUBLE and DECIMAL are such.
DECIMAL columns store values with exact precision because they are
represented as strings, but calculations on DECIMAL values may be done
using floating-point operations.
The following example demonstrate the problem. It shows that even for the
DECIMAL column type, calculations that are done using floating-point
operations are subject to floating-point error.
mysql> CREATE TABLE t1 (i INT, d1 DECIMAL(9,2), d2 DECIMAL(9,2));
mysql> INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),
-> (2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),
-> (2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),
-> (4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),
-> (5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),
-> (6, 0.00, 0.00), (6, -51.40, 0.00);
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+--------+-------+
| i | a | b |
+------+--------+-------+
| 1 | 21.40 | 21.40 |
| 2 | 76.80 | 76.80 |
| 3 | 7.40 | 7.40 |
| 4 | 15.40 | 15.40 |
| 5 | 7.20 | 7.20 |
| 6 | -51.40 | 0.00 |
+------+--------+-------+
The result is correct. Although the first five records look like they
shouldn't pass the comparison test (the values of a and b do
not appear to be different), they may do so because the difference between
the numbers shows up around tenth decimal or so, depending on computer
architecture.
The problem cannot be solved by using ROUND() or similar functions,
because the result is still a floating-point number:
mysql> SELECT i, ROUND(SUM(d1), 2) AS a, ROUND(SUM(d2), 2) AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+--------+-------+
| i | a | b |
+------+--------+-------+
| 1 | 21.40 | 21.40 |
| 2 | 76.80 | 76.80 |
| 3 | 7.40 | 7.40 |
| 4 | 15.40 | 15.40 |
| 5 | 7.20 | 7.20 |
| 6 | -51.40 | 0.00 |
+------+--------+-------+
This is what the numbers in column a look like when displayed with more
decimal places:
mysql> SELECT i, ROUND(SUM(d1), 2)*1.0000000000000000 AS a,
-> ROUND(SUM(d2), 2) AS b FROM t1 GROUP BY i HAVING a <> b;
+------+----------------------+-------+
| i | a | b |
+------+----------------------+-------+
| 1 | 21.3999999999999986 | 21.40 |
| 2 | 76.7999999999999972 | 76.80 |
| 3 | 7.4000000000000004 | 7.40 |
| 4 | 15.4000000000000004 | 15.40 |
| 5 | 7.2000000000000002 | 7.20 |
| 6 | -51.3999999999999986 | 0.00 |
+------+----------------------+-------+
Depending on your computer architecture, you may or may not see similar
results. Different CPUs may evaluate floating-point numbers differently.
For example, on some machines you may get the ``correct'' results by
multiplying both arguments by 1, as the following example shows.
Warning: Never use this method in your applications. It is not
an example of a trustworthy method!
mysql> SELECT i, ROUND(SUM(d1), 2)*1 AS a, ROUND(SUM(d2), 2)*1 AS b
-> FROM t1 GROUP BY i HAVING a <> b;
+------+--------+------+
| i | a | b |
+------+--------+------+
| 6 | -51.40 | 0.00 |
+------+--------+------+
The reason that the preceding example seems to work is that on the particular
machine where the test was done, CPU floating-point arithmetic happens to
round the numbers to the same value. However, there is no rule that any CPU
should do so, so this method cannot be trusted.
The correct way to do floating-point number comparison is to first
decide on what is the desired tolerance between the numbers and then do
the comparison against the tolerance value. For example, if we agree
that floating-point numbers should be regarded the same if they are
same within a precision of one in ten thousand (0.0001), the comparison
should be written to find differences larger than the tolerance value:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) > 0.0001;
+------+--------+------+
| i | a | b |
+------+--------+------+
| 6 | -51.40 | 0.00 |
+------+--------+------+
1 row in set (0.00 sec)
Conversely, if we wanted to get rows where the numbers are the same,
the test should find differences within the tolerance value:
mysql> SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1
-> GROUP BY i HAVING ABS(a - b) < 0.0001;
+------+-------+-------+
| i | a | b |
+------+-------+-------+
| 1 | 21.40 | 21.40 |
| 2 | 76.80 | 76.80 |
| 3 | 7.40 | 7.40 |
| 4 | 15.40 | 15.40 |
| 5 | 7.20 | 7.20 |
+------+-------+-------+
MySQL uses a cost-based optimizer to determine the best way to resolve a
query. In many cases, MySQL can calculate the best possible query plan,
but sometimes MySQL doesn't have enough information about the data
at hand and has to make ``educated'' guesses about the data.
This section is intended for the cases when MySQL doesn't get it right.
The tools you have available to help MySQL do the ``right'' things are:
The output from EXPLAIN will show ALL in the type
column when MySQL uses a table scan to resolve a query. This usually happens
under the following conditions:
-
The table is so small that it's faster to do a table scan than a key lookup.
This is a common case for tables with fewer than 10 rows and a short row length.
-
There are no usable restrictions in the
ON or WHERE clause
for indexed columns.
-
You are comparing indexed columns with constants and MySQL has
calculated (based on the index tree) that the constants cover too large a
part of the table and that a table scan would be faster.
See section 7.2.4 How MySQL Optimizes
WHERE Clauses.
-
You are using a key with low cardinality (many rows match the key value)
through another column. MySQL will in this case assume that by using the
key it will probably do a lot of key lookups and that a table scan
would be faster.
For small tables, a table scan often is appropriate. For large tables, try
the following techniques to to avoid having the optimizer incorrectly choose
a table scan:
ALTER TABLE changes a table to the current character set.
If you get a duplicate-key error during ALTER TABLE, the cause
is either that the new character sets maps two keys to the same value
or that the table is corrupted. In the latter case, you should run
REPAIR TABLE on the table.
If ALTER TABLE dies with the following error, the problem may be that
MySQL crashed during an earlier ALTER TABLE operation and there is an
old table named `A-something' or `B-something' lying around:
Error on rename of './database/name.frm'
to './database/B-a.frm' (Errcode: 17)
In this case, go to the MySQL data directory and delete all files that have
names starting with A- or B-. (You may want to move them
elsewhere instead of deleting them.)
ALTER TABLE works the following way:
-
Create a new table named `A-xxx' with the requested structural changes.
-
Copy all rows from the original table to `A-xxx'.
-
Rename the original table to `B-xxx'.
-
Rename `A-xxx' to your original table name.
-
Delete `B-xxx'.
If something goes wrong with the renaming operation, MySQL tries to
undo the changes. If something goes seriously wrong (although this shouldn't
happen), MySQL may leave the old table as `B-xxx', but a
simple rename of the table files at the system level should get your data back.
If you use ALTER TABLE on a transactional table or if you are using
Windows or OS/2, ALTER TABLE will UNLOCK the table if you had
done a LOCK TABLE on it. This is because InnoDB and these
operating systems cannot drop a table that is in use.
First, consider whether you really need to change the column order in a
table. The whole point of SQL is to abstract the application from the data
storage format. You should always specify the order in which you wish to
retrieve your data. The first of the following statements returns columns
in the order col_name1, col_name2, col_name3, whereas
the second returns them in the order col_name1, col_name3,
col_name2:
mysql> SELECT col_name1, col_name2, col_name3 FROM tbl_name;
mysql> SELECT col_name1, col_name3, col_name2 FROM tbl_name;
If you decide to change the order of table columns anyway, you can do so as
follows:
-
Create a new table with the columns in the new order.
-
Execute this statement:
mysql> INSERT INTO new_table
-> SELECT columns-in-new_table-order FROM old_table;
-
Drop or rename
old_table.
-
Rename the new table to the original name:
mysql> ALTER TABLE new_table RENAME old_table;
SELECT * is quite suitable for testing queries. However, in an
application, you should never rely on using SELECT * and
retrieving the columns based on their position. The order and position
in which columns are returned will not remain the same if you add, move,
or delete columns. A simple change to your table structure will then cause
your application to fail.
The following list indicates limitations on the use of TEMPORARY
tables:
-
A
TEMPORARY table can only be of type HEAP, ISAM,
MyISAM, MERGE, or InnoDB.
-
You cannot refer to a
TEMPORARY table more than once in the same query.
For example, the following does not work.
mysql> SELECT * FROM temp_table, temp_table AS t2;
ERROR 1137: Can't reopen table: 'temp_table'
-
The
SHOW TABLES statement does not list TEMPORARY tables.
-
You cannot use
RENAME to rename a TEMPORARY table. However,
you can use ALTER TABLE instead:
mysql> ALTER TABLE orig_name RENAME new_name;
Go to the first, previous, next, last section, table of contents.
|