![]() |
|
|
Go to the first, previous, next, last section, table of contents.
A Problems and Common ErrorsThis appendix lists some common problems and error messages that you may encounter. It describes how to determine the causes of the problems and what to do to solve them. A.1 How to Determine What Is Causing a ProblemWhen 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 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:
When sending a bug report, you should follow the outline described in section 1.4.1.2 Asking Questions or Reporting Bugs. A.2 Common Errors When Using MySQL ProgramsThis section lists some errors that users frequently encounter when running MySQL programs. Although the problems show up when you try to run client programs, the solutions to many of the problems involves changing the configuration of the MySQL server. A.2.1
|
|||||||||||||
| 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. |
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. This assumes that you have automatic
reconnection in the client enabled (which is the default for the mysql
command-line client).
Some other common reasons for the MySQL server has gone away error are:
KILL statement or a mysqladmin kill command.
mysql_options(..., MYSQL_OPT_READ_TIMEOUT,...) or
mysql_options(..., MYSQL_OPT_WRITE_TIMEOUT,...). In this case
increasing the timeout may help solve the problem.
reconnect flag
in the MYSQL structure is equal to 0).
wait_timeout expired) before the command was
issued.
The problem on windows is that in some cases MySQL doesn't get an error
from the OS when writing to the TCP/IP connection to the server, but
instead gets the error when trying to read the answer from connection.
In this case, even if the reconnect flag in the MYSQL structure
is equal to 1, MySQL will not automatically reconnect and re-issue the query as
it doesn't know if the server did get the original query or not.
The solution to this is to either do a mysql_ping on the
connection if there has been a long time since the last query (this is
what MyODBC does) or set wait_timeout on the mysqld
server so high that it will in practice never time out.
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.9 Packet too large.
MySQL server has gone away error if MySQL
is started with the --skip-networking option.
You can check whether the MySQL server died and restarted by executing
mysqladmin version and examining the server's uptime. If the
client connection was broken because mysqld crashed and restarted,
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.2 What to Do If MySQL Keeps Crashing.
You can get more information about the lost connections by starting
mysqld with the --log-warnings=2 option. This will log some of the
disconnected errors in the hostname.err file. See section 5.9.1 The Error Log.
If you want to create a bug report regarding this problem, be sure that you include the following information:
mysqld and the tables involved were
checked with CHECK TABLE before you ran the query, can you provide a
reproducible test case?
See section E.1.6 Making a Test Case If You Experience Table Corruption.
wait_timeout system variable in the MySQL
server? (mysqladmin variables gives you the value of this variable.)
mysqld with the --log option to
determine whether the problem query appears in the log?
See also See section A.2.10 Communication Errors and Aborted Connections.
See section 1.4.1.2 Asking Questions or Reporting Bugs.
Packet too largeA 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.
Both the client and the server have their own
max_allowed_packet variable, so if you want to handle big packets,
you must 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 server'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 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 restarting mysqld.
The server error log can be a useful source of information about connection
problems.
See section 5.9.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:
mysql_close() before exiting.
wait_timeout or
interactive_timeout seconds without issuing any requests to the server.
See section 5.2.3 Server System Variables.
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:
connect_timeout seconds to get
a connect packet.
See section 5.2.3 Server System Variables.
If these kinds of things happen, it might indicate that someone is trying to break into your server!
Other reasons for problems with aborted clients or aborted connections:
max_allowed_packet variable value is too small or queries require
more memory than you have allocated for mysqld.
See section A.2.9 Packet too large.
See also See section A.2.8 MySQL server has gone away.
The table is fullThere are several ways a full-table error can occur:
tmp_table_size bytes.
To avoid this problem, you can use the -O tmp_table_size=# option
to make mysqld increase the temporary table size or use the SQL
option SQL_BIG_TABLES before you issue the problematic query.
See section 13.5.3 SET Syntax.
You can also start mysqld with the --big-tables option.
This is exactly the same as using SQL_BIG_TABLES for all queries.
As of MySQL 3.23, this problem should not occur. If an in-memory temporary
table becomes larger than tmp_table_size, the server automatically
converts it to a disk-based MyISAM table.
InnoDB tables and run out of room in the
InnoDB tablespace. In this case, the solution is to extend the
InnoDB tablespace.
See section 15.8 Adding and Removing InnoDB Data and Log Files.
ISAM or MyISAM tables on an operating system
that supports files only up to 2GB in size and you have hit this limit for the
data file or index file.
MyISAM table and the space required for the table
exceeds what is allowed by the internal pointer size. (If you don't specify
the MAX_ROWS table option when you create a table, MySQL
uses the myisam_data_pointer_size system variable. Its default value of
4 bytes is enough to allow only 4GB of data.)
See section 5.2.3 Server System Variables.
You can check the maximum data/index sizes by using this statement:
SHOW TABLE STATUS FROM database LIKE 'tbl_name';You also can use
myisamchk -dv /path/to/table-index-file.
If the pointer size is too small, you can fix the problem by using ALTER
TABLE:
ALTER TABLE tbl_name MAX_ROWS=1000000000 AVG_ROW_LENGTH=nnn;You have to specify
AVG_ROW_LENGTH only for tables with BLOB
or TEXT columns; in this case, MySQL can't optimize the space
required based only on the number of rows.
Can't create/write to fileIf you get an error of the following type for some queries, it means that MySQL cannot 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 message for Windows; the Unix message is similar.
One 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 and have sufficient space for the MySQL server to write to. See section 4.3.2 Using Option Files.
Another cause of this error can be permissions issues. Make sure that the MySQL
server can write to the tmpdir directory.
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
Commands out of sync
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.
Ignoring user
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:
mysqld with an old user
table. You can check this by executing mysqlshow mysql user to see
whether the Password column is shorter than 16 characters. If so, you
can correct this condition by running the scripts/add_long_password
script.
mysqld with the --old-protocol option.
Update the account in the user table to have a new password or
restart mysqld with the --old-protocol option.
user table without using the
PASSWORD() function. Use mysql to update the account in the
user table with a new password, making sure to use the PASSWORD()
function:
mysql> UPDATE user SET Password=PASSWORD('newpwd')
-> WHERE User='some_user' AND Host='some_host';
Table 'tbl_name' doesn't existIf you get either of the following errors, it usually means that no table exists in the current database with the given name:
Table 'tbl_name' doesn't exist Can't find file: 'tbl_name' (errno: 2)
In some cases, it may be that the table does exist but that you are referring to it incorrectly:
You can check which tables are in the current database with
SHOW TABLES. See section 13.5.4 SHOW Syntax.
Can't initialize character setYou might see an error like this if you have character set problems:
MySQL Connection Failed: Can't initialize character set charset_name
This error can have any of the following causes:
configure
with the --with-charset=charset_name or
--with-extra-charsets=charset_name
option.
See section 2.8.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.8.1 The Character Set Used for Data and Sorting.
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:
configure Options.
--character-sets-dir option.
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 Error code 23: File table overflow shell> perror 24 Error code 24: Too many open files shell> perror 11 Error code 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 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 set the number of file
descriptors to be made 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 be overridden only 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 so
that it does not continue to run as root after it starts up).
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 determine the correct directory, try this command:
shell> mysql_config --libs
The output from mysql_config 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 function, add -lz to the end of your
link command and try again.
If you get undefined reference errors for a function 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.8 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 specify symbols that start with mysql_
or indicate 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:
LD_LIBRARY_PATH environment variable.
LD_LIBRARY environment variable.
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:
mysqladmin shutdown).
root user):
shell> chown -R user_name /path/to/mysql/datadirIf you do not do this, the server will not be able to access databases or tables when it runs as user_name. 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.
mysqld as the Unix root
user and use the --user=user_name option. mysqld will start up,
then switch
to run as the Unix user user_name before accepting any connections.
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
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 the mysql client 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.9 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> 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> 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 F Environment Variables.
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.4.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:
Start Menu -> Control Panel -> Administrative Tools -> ServicesThen 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.
Start Menu -> Run -> cmd
C:\> C:\mysql\bin\mysqld-nt --skip-grant-tablesThis starts the server in a special mode that does not check the grant tables to control access.
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.
In a Unix environment, the procedure for resetting the root password
is as follows:
root user or as the
same user that the mysqld server runs as.
kill
(not kill -9) to the mysqld process, using the pathname of the
`.pid' file in the following command:
shell> kill `cat /mysql-data-directory/host_name.pid`Note the use of backticks rather than forward quotes with the
cat
command; these cause the output of cat
to be substituted into the kill command.
--skip-grant-tables option:
shell> mysqld_safe --skip-grant-tables &
root@localhost MySQL account:
shell> mysqladmin -u root flush-privileges password "newpwd"Replace ``newpwd'' with the actual
root password that you want
to use.
Alternatively, on any platform, you can set the new password using the mysql client:
mysqld and restart it with the --skip-grant-tables
option as described earlier.
mysqld server with this command:
shell> mysql -u root
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.
Each MySQL version is tested on many platforms before it is 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, because 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.9.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 E.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 data files 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
data files are written but not index files.) This means that data file
contents are 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:
mysqld that caused it to die in the
middle of an update.
mysqld without locking the table properly.
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.
mysqld.
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:
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.
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.9.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.4.1.3 How to Report Bugs or Problems.
fork_big.pl script. (It is located in the `tests'
directory of source distributions.)
--with-debug
or --with-debug=full option to configure and then recompile.
See section E.1 Debugging a MySQL Server.
--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.)
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.
mysqladmin -i 5 status or mysqladmin -i 5
-r status in a separate window to produce statistics while you run
your other queries.
mysqld from gdb (or another debugger).
See section E.1.3 Debugging mysqld under gdb.
gdb, you can do this with the following commands when mysqld
has crashed inside gdb:
backtrace info local up info local up info localWith
gdb, you can also examine which threads exist with info
threads and switch to a specific thread with thread #, where
# is the thread ID.
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 dynamic-length rows are by nature more prone to
errors, so it may be a good idea to try this strategy to see whether it helps.
This section describes how MySQL responds to disk-full errors (such as ``no space left on device''), and, as of MySQL 4.0.22, to quota-exceeded errors (such as ``write failed'' or ``user block limit reached").
This section is relevant for writes to MyISAM tables. As of MySQL
4.1.9, it also applies for writes to binary log files and binary log index
file, except that references to ``row'' and ``record'' should be understood
to mean ``event.''
When a disk-full condition occurs, MySQL does the following:
To alleviate the problem, you can take the following actions:
mysqladmin kill.
The thread will be aborted the next time it checks the disk (in one minute).
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, if 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 the load
effectively, these paths should be located 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:
/etc/my.cnf:
[mysqld] socket=/path/to/socket [client] socket=/path/to/socketSee section 4.3.2 Using Option Files.
--socket option on the command line
to mysqld_safe and when you run client programs.
MYSQL_UNIX_PORT environment variable to the path of the Unix
socket file.
--with-unix-socket-path option when you run configure.
See section 2.8.2 Typical configure Options.
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 F 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 13.2.6 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);
DATE Columns
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
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
MyODBC, it is automatically converted to NULL in
MyODBC 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.
If you are using the ALLOW_INVALID_DATES SQL mode, MySQL allows you to
store dates that are given only limited checking: MySQL ensures only that the
day is in the range from 1 to 31 and the month is in the range from 1 to 12.
This makes MySQL very convenient for Web applications where you obtain year, month, and day in three different fields and you want to store exactly what the user inserted (without date validation).
If you are not using the NO_ZERO_IN_DATE SQL mode, the day or month
part can be zero. This is convenient if you want to store a birthdate
in a DATE column and you know only part of the date.
If you are not using the NO_ZERO_DATE SQL mode, MySQL also allows
you to store '0000-00-00' as a ``dummy date.'' This is in some cases
more convenient than using NULL values.
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 a 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.
If you want MySQL to check all dates and accept only legal dates
(unless overriden by IGNORE), you should set sql_mode to
"NO_ZERO_IN_DATE,NO_ZERO_DATE".
Date handling in MySQL 5.0.1 and earlier works like MySQL 5.0.2 with the
ALLOW_INVALID_DATES SQL mode enabled.
NULL Values
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 an expr = 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 show how 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 if you are using MySQL 3.23.2 or newer and are using the
MyISAM, InnoDB, or BDB storage engine.
As of MySQL 4.0.2, the MEMORY storage engine also supports NULL
values in indexes. Otherwise, you must declare an indexed column NOT
NULL and you cannot insert NULL into the 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 13.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
integer column that has the AUTO_INCREMENT attribute, 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 root FROM tbl_name GROUP BY root HAVING root > 0; SELECT id, COUNT(*) AS cnt FROM tbl_name GROUP BY id HAVING cnt > 0; SELECT id AS 'Customer identity' FROM tbl_name;
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.
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 13.5.4.17 SHOW TABLE STATUS Syntax and
section 13.5.4.5 SHOW CREATE TABLE Syntax.
You can check which storage engines your mysqld server supports by
using this statement:
SHOW ENGINES;
Before MySQL 4.1.2, SHOW ENGINES is unavailable. 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 13.5.4.8 SHOW ENGINES Syntax and
section 13.5.4.19 SHOW VARIABLES Syntax.
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 1,000 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:
EXPLAIN to check whether you can find something
that is obviously wrong.
See section 7.2.1 EXPLAIN Syntax (Get Information About a SELECT).
WHERE clause.
LIMIT 10 with the query.
SELECT for the column that should have matched a row against
the table that was last removed from the query.
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.8 Problems with Floating-Point Comparisons.
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 more than needed to demonstrate
the problem), and add your SELECT statement at the end of the file.
Verify that the test file demonstrates the problem by executing these
commands:
shell> mysqladmin create test2 shell> mysql test2 < query.sqlPost the test file using
mysqlbug to the general MySQL mailing list.
See section 1.4.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 the 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 an acceptable tolerance for differences 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, 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.
For the cases when MySQL does not do the "right" thing, tools that you have available to help MySQL are:
EXPLAIN statement to get information about how MySQL will
process a query. To use it, just add the keyword EXPLAIN to the
front of your SELECT statement:
mysql> EXPLAIN SELECT * FROM t1, t2 WHERE t1.i = t2.i;
EXPLAIN is discussed in more detail in section 7.2.1 EXPLAIN Syntax (Get Information About a SELECT).
ANALYZE TABLE tbl_name to update the key distributions for the
scanned table. See section 13.5.2.1 ANALYZE TABLE Syntax.
FORCE INDEX for the scanned table to tell MySQL that table
scans are very expensive compared to using the given index.
See section 13.1.7 SELECT Syntax.
SELECT * FROM t1, t2 FORCE INDEX (index_for_column) WHERE t1.col_name=t2.col_name;
USE INDEX and IGNORE INDEX may also be useful.
STRAIGHT_JOIN. See section 13.1.7 SELECT Syntax.
mysqld with the --max-seeks-for-key=1000 option or use
SET max_seeks_for_key=1000 to tell the optimizer to assume that no
key scan will cause more than 1,000 key seeks.
See section 5.2.3 Server System Variables.
ALTER TABLE
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-xxx' or `B-xxx' lying around:
Error on rename of './database/name.frm' to './database/B-xxx.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 in the following way:
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'. 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:
mysql> INSERT INTO new_table
-> SELECT columns-in-new-order FROM old_table;
old_table.
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 cause
your application to fail.
TEMPORARY TABLE Problems
The following list indicates limitations on the use of TEMPORARY
tables:
TEMPORARY table can only be of type HEAP, ISAM,
MyISAM, MERGE, or InnoDB.
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'
SHOW TABLES statement does not list TEMPORARY tables.
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.
| Copyright © 2004-2006 PHPJK.com | ![]() |