Appendix D. Restrictions and Limits
Table of Contents
The discussion here describes restrictions that apply to the use of MySQL features such as subqueries or views.
Some of the restrictions noted here apply to all stored routines; that is, both to stored procedures and stored functions. Some of these restrictions apply to stored functions but not to stored procedures.
The restrictions for stored functions also apply to triggers. There are also some restrictions specific to triggers.
The restrictions for stored procedures also apply to the
DO clause of Event Scheduler event
definitions. There are also some restrictions specific to events.
Stored routines cannot contain arbitrary SQL statements. The following statements are disallowed:
The locking statements
LOCK TABLESandUNLOCK TABLES.LOAD DATAandLOAD TABLE.SQL prepared statements (
PREPARE,EXECUTE,DEALLOCATE PREPARE) can be used in stored procedures, but not stored functions or triggers. Implication: You cannot use dynamic SQL within stored functions or triggers (where you construct dynamically statements as strings and then execute them).In addition, SQL statements that are not permitted within prepared statements are also not permitted in stored routines. See Section 12.7, “SQL Syntax for Prepared Statements”, for a list of statements supported as prepared statements. Statements not listed there are not supported for SQL prepared statements and thus are also not supported for stored routines unless noted otherwise in Section 18.2, “Using Stored Routines (Procedures and Functions)”.
Inserts cannot be delayed.
INSERT DELAYEDsyntax is accepted but the statement is handled as a normalINSERT.Within all stored programs (stored procedures and functions, triggers, and events), the parser treats
BEGIN [WORK]as the beginning of aBEGIN ... ENDblock. Begin a transaction in this context withSTART TRANSACTIONinstead.
For stored functions (but not stored procedures), the following additional statements or operations are disallowed:
Statements that perform explicit or implicit commit or rollback. Support for these statements is not required by the SQL standard, which states that each DBMS vendor may decide whether to allow them.
Statements that return a result set. This includes
SELECTstatements that do not have anINTOclause and other statements such asvar_listSHOW,EXPLAIN, andCHECK TABLE. A function can process a result set either withSELECT ... INTOor by using a cursor andvar_listFETCHstatements. See Section 12.8.3.3, “SELECT ... INTOStatement”.FLUSHstatements.Stored functions cannot be used recursively.
Within a stored function or trigger, it is not permitted to modify a table that is already being used (for reading or writing) by the statement that invoked the function or trigger.
If you refer to a temporary table multiple times in a stored function under different aliases, a
Can't reopen table: 'error occurs, even if the references occur in different statements within the function.tbl_name'A stored function acquires table locks before executing, to avoid inconsistency in the binary log due to mismatch of the order in which statements execute and when they appear in the log. When statement-based binary logging is used, statements that invoke a function are recorded rather than the statements executed within the function. Consequently, stored functions that update the same underlying tables do not execute in parallel. In contrast, stored procedures do not acquire table-level locks. All statements executed within stored procedures are written to the binary log even for statement-based binary logging. See Section 18.6, “Binary Logging of Stored Programs”.
Although some restrictions normally apply to stored functions and
triggers but not to stored procedures, those restrictions do apply
to stored procedures if they are invoked from within a stored
function or trigger. For example, if you use
FLUSH in a stored procedure, that
stored procedure cannot be called from a stored function or
trigger.
It is possible for the same identifier to be used for a routine parameter, a local variable, and a table column. Also, the same local variable name can be used in nested blocks. For example:
CREATE PROCEDURE p (i INT)
BEGIN
DECLARE i INT DEFAULT 0;
SELECT i FROM t;
BEGIN
DECLARE i INT DEFAULT 1;
SELECT i FROM t;
END;
END;
In such cases the identifier is ambiguous and the following precedence rules apply:
A local variable takes precedence over a routine parameter or table column
A routine parameter takes precedence over a table column
A local variable in an inner block takes precedence over a local variable in an outer block
The behavior that variables take precedence over table columns is nonstandard.
Use of stored routines can cause replication problems. This issue is discussed further in Section 18.6, “Binary Logging of Stored Programs”.
INFORMATION_SCHEMA does not have a
PARAMETERS table until MySQL 6.0, so
applications that need to acquire routine parameter information at
runtime must use workarounds such as parsing the output of
SHOW CREATE statements or the
param_list column of the
mysql.proc table. param_list
contents can be processed from within a stored routine, unlike the
output from SHOW.
There are no stored routine debugging facilities.
UNDO handlers are not supported.
FOR loops are not supported.
To prevent problems of interaction between server threads, when a client issues a statement, the server uses a snapshot of routines and triggers available for execution of the statement. That is, the server calculates a list of procedures, functions, and triggers that may be used during execution of the statement, loads them, and then proceeds to execute the statement. This means that while the statement executes, it will not see changes to routines performed by other threads.
For triggers, the following additional statements or operations are disallowed:
Triggers currently are not activated by foreign key actions.
When using row-based replication, triggers on the slave are not activated by statements originating on the master. This does not apply when using statement-based replication. For more information, see Section 16.3.1.26, “Replication and Triggers”.
The
RETURNstatement is disallowed in triggers, which cannot return a value. To exit a trigger immediately, use theLEAVEstatement.Triggers are not allowed on tables in the
mysqldatabase.
The following limitations are specific to the Event Scheduler:
Event names are handled in case-insensitive fashion. For example, this means that you cannot have two events in the same database with the names
anEventandAnEvent.An event may not be created, altered, or dropped by a stored routine, trigger, or another event. An event also may not create, alter, or drop stored routines or triggers. (Bug#16409, Bug#18896)
Event timings using the intervals
YEAR,QUARTER,MONTH, andYEAR_MONTHare resolved in months; those using any other interval are resolved in seconds. There is no way to cause events scheduled to occur at the same second to execute in a given order. In addition — due to rounding, the nature of threaded applications, and the fact that a nonzero length of time is required to create events and to signal their execution — events may be delayed by as much as 1 or 2 seconds. However, the time shown in theINFORMATION_SCHEMA.EVENTStable'sLAST_EXECUTEDcolumn or themysql.eventtable'slast_executedcolumn is always accurate to within one second of the actual event execution time. (See also Bug#16522.)Each execution of the statements contained in the body of an event takes place in a new connection; thus, these statements has no effect in a given user session on the server's statement counts such as
Com_selectandCom_insertthat are displayed bySHOW STATUS. However, such counts are updated in the global scope. (Bug#16422)Events do not support times later than the end of the Unix Epoch; this is approximately the beginning of the year 2038. Such dates are specifically disallowed by the Event Scheduler. (Bug#16396)
References to stored functions, user-defined functions, and tables in the
ON SCHEDULEclauses ofCREATE EVENTandALTER EVENTstatements are not supported. These sorts of references are disallowed. (See Bug#22830 for more information.)Generally speaking, statements which are not permitted in stored routines or in SQL prepared statements are also not allowed in the body of an event. For more information, see Section 12.7, “SQL Syntax for Prepared Statements”.
Stored routines and triggers in MySQL Cluster.
Stored functions, stored procedures, and triggers are all
supported by tables using the NDB
storage engine; however, it is important to keep in mind that
they do not propagate automatically between
MySQL Servers acting as Cluster SQL nodes. This is because of
the following:
Stored routine definitions are kept in tables in the
mysqlsystem database using theMyISAMstorage engine, and so do not participate in clustering.The
.TRNand.TRGfiles containing trigger definitions are not read by theNDBstorage engine, and are not copied between Cluster nodes.
Any stored routine or trigger that interacts with MySQL Cluster
tables must be re-created by running the appropriate
CREATE PROCEDURE,
CREATE FUNCTION, or
CREATE TRIGGER statements on each
MySQL Server that participates in the cluster where you wish to
use the stored routine or trigger. Similarly, any changes to
existing stored routines or triggers must be carried out
explicitly on all Cluster SQL nodes, using the appropriate
ALTER or DROP statements
on each MySQL Server accessing the cluster.
Warning
Do not attempt to work around the issue
described in the first item mentioned previously by
converting any mysql database tables to
use the NDB storage engine.
Altering the system tables in the
mysql database is not
supported and is very likely to produce
undesirable results.
Server-side cursors are implemented in the C API via the
mysql_stmt_attr_set() function.
The same implementation is used for cursors in stored routines. A
server-side cursor allows a result set to be generated on the
server side, but not transferred to the client except for those
rows that the client requests. For example, if a client executes a
query but is only interested in the first row, the remaining rows
are not transferred.
In MySQL, a server-side cursor is materialized into a temporary
table. Initially, this is a MEMORY table, but
is converted to a MyISAM table if its size
reaches the value of the
max_heap_table_size system
variable. One limitation of the implementation is that for a large
result set, retrieving its rows through a cursor might be slow.
Cursors are read only; you cannot use a cursor to update rows.
UPDATE WHERE CURRENT OF and DELETE
WHERE CURRENT OF are not implemented, because updatable
cursors are not supported.
Cursors are nonholdable (not held open after a commit).
Cursors are asensitive.
Cursors are nonscrollable.
Cursors are not named. The statement handler acts as the cursor ID.
You can have open only a single cursor per prepared statement. If you need several cursors, you must prepare several statements.
You cannot use a cursor for a statement that generates a result
set if the statement is not supported in prepared mode. This
includes statements such as CHECK
TABLE, HANDLER READ, and
SHOW BINLOG EVENTS.
A subquery's outer statement can be any one of:
SELECT,INSERT,UPDATE,DELETE,SET, orDO.Subquery optimization for
INis not as effective as for the=operator or for theIN(operator.value_list)A typical case for poor
INsubquery performance is when the subquery returns a small number of rows but the outer query returns a large number of rows to be compared to the subquery result.The problem is that, for a statement that uses an
INsubquery, the optimizer rewrites it as a correlated subquery. Consider the following statement that uses an uncorrelated subquery:SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);
The optimizer rewrites the statement to a correlated subquery:
SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);
If the inner and outer queries return
MandNrows, respectively, the execution time becomes on the order ofO(, rather thanM×N)O(as it would be for an uncorrelated subquery.M+N)An implication is that an
INsubquery can be much slower than a query written using anIN(operator that lists the same values that the subquery would return.value_list)In general, you cannot modify a table and select from the same table in a subquery. For example, this limitation applies to statements of the following forms:
DELETE FROM t WHERE ... (SELECT ... FROM t ...); UPDATE t ... WHERE col = (SELECT ... FROM t ...); {INSERT|REPLACE} INTO t (SELECT ... FROM t ...);Exception: The preceding prohibition does not apply if you are using a subquery for the modified table in the
FROMclause. Example:UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);
Here the prohibition does not apply because the result from a subquery in the
FROMclause is stored as a temporary table, so the relevant rows inthave already been selected by the time the update tottakes place.Row comparison operations are only partially supported:
For
,exprIN (subquery)exprcan be ann-tuple (specified via row constructor syntax) and the subquery can return rows ofn-tuples.For
,exprop{ALL|ANY|SOME} (subquery)exprmust be a scalar value and the subquery must be a column subquery; it cannot return multiple-column rows.
In other words, for a subquery that returns rows of
n-tuples, this is supported:(
val_1, ...,val_n) IN (subquery)But this is not supported:
(
val_1, ...,val_n)op{ALL|ANY|SOME} (subquery)The reason for supporting row comparisons for
INbut not for the others is thatINis implemented by rewriting it as a sequence of=comparisons andANDoperations. This approach cannot be used forALL,ANY, orSOME.Row constructors are not well optimized. The following two expressions are equivalent, but only the second can be optimized:
(col1, col2, ...) = (val1, val2, ...) col1 = val1 AND col2 = val2 AND ...
Subqueries in the
FROMclause cannot be correlated subqueries. They are materialized (executed to produce a result set) before evaluating the outer query, so they cannot be evaluated per row of the outer query.The optimizer is more mature for joins than for subqueries, so in many cases a statement that uses a subquery can be executed more efficiently if you rewrite it as a join.
An exception occurs for the case where an
INsubquery can be rewritten as aSELECT DISTINCTjoin. Example:SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE
condition);That statement can be rewritten as follows:
SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND
condition;But in this case, the join requires an extra
DISTINCToperation and is not more efficient than the subquery.Possible future optimization: MySQL does not rewrite the join order for subquery evaluation. In some cases, a subquery could be executed more efficiently if MySQL rewrote it as a join. This would give the optimizer a chance to choose between more execution plans. For example, it could decide whether to read one table or the other first.
Example:
SELECT a FROM outer_table AS ot WHERE a IN (SELECT a FROM inner_table AS it WHERE ot.b = it.b);
For that query, MySQL always scans
outer_tablefirst and then executes the subquery oninner_tablefor each row. Ifouter_tablehas a lot of rows andinner_tablehas few rows, the query probably will not be as fast as it could be.The preceding query could be rewritten like this:
SELECT a FROM outer_table AS ot, inner_table AS it WHERE ot.a = it.a AND ot.b = it.b;
In this case, we can scan the small table (
inner_table) and look up rows inouter_table, which will be fast if there is an index on(ot.a,ot.b).Possible future optimization: A correlated subquery is evaluated for each row of the outer query. A better approach is that if the outer row values do not change from the previous row, do not evaluate the subquery again. Instead, use its previous result.
Possible future optimization: A subquery in the
FROMclause is evaluated by materializing the result into a temporary table, and this table does not use indexes. This does not allow the use of indexes in comparison with other tables in the query, although that might be useful.Possible future optimization: If a subquery in the
FROMclause resembles a view to which the merge algorithm can be applied, rewrite the query and apply the merge algorithm so that indexes can be used. The following statement contains such a subquery:SELECT * FROM (SELECT * FROM t1 WHERE t1.t1_col) AS _t1, t2 WHERE t2.t2_col;The statement can be rewritten as a join like this:
SELECT * FROM t1, t2 WHERE t1.t1_col AND t2.t2_col;
This type of rewriting would provide two benefits:
It avoids the use of a temporary table for which no indexes can be used. In the rewritten query, the optimizer can use indexes on
t1.It gives the optimizer more freedom to choose between different execution plans. For example, rewriting the query as a join allows the optimizer to use
t1ort2first.
Possible future optimization: For
IN,= ANY,<> ANY,= ALL, and<> ALLwith uncorrelated subqueries, use an in-memory hash for a result or a temporary table with an index for larger results. Example:SELECT a FROM big_table AS bt WHERE non_key_field IN (SELECT non_key_field FROM
tableWHEREcondition)In this case, we could create a temporary table:
CREATE TABLE t (key (non_key_field)) (SELECT non_key_field FROM
tableWHEREcondition)Then, for each row in
big_table, do a key lookup intbased onbt.non_key_field.
View processing is not optimized:
It is not possible to create an index on a view.
Indexes can be used for views processed using the merge algorithm. However, a view that is processed with the temptable algorithm is unable to take advantage of indexes on its underlying tables (although indexes can be used during generation of the temporary tables).
Subqueries cannot be used in the FROM clause of
a view.
There is a general principle that you cannot modify a table and select from the same table in a subquery. See Section D.3, “Restrictions on Subqueries”.
The same principle also applies if you select from a view that selects from the table, if the view selects from the table in a subquery and the view is evaluated using the merge algorithm. Example:
CREATE VIEW v1 AS SELECT * FROM t2 WHERE EXISTS (SELECT 1 FROM t1 WHERE t1.a = t2.a); UPDATE t1, v2 SET t1.a = 1 WHERE t1.b = v2.b;
If the view is evaluated using a temporary table, you
can select from the table in the view
subquery and still modify that table in the outer query. In this
case the view will be stored in a temporary table and thus you are
not really selecting from the table in a subquery and modifying it
“at the same time.” (This is another reason you might
wish to force MySQL to use the temptable algorithm by specifying
ALGORITHM = TEMPTABLE in the view definition.)
You can use DROP TABLE or
ALTER TABLE to drop or alter a
table that is used in a view definition. No warning results from
the DROP or ALTER operation,
even though this invalidates the view. Instead, an error occurs
later, when the view is used. CHECK
TABLE can be used to check for views that have been
invalidated by DROP or ALTER
operations.
A view definition is “frozen” by certain statements:
If a statement prepared by
PREPARErefers to a view, the view definition seen each time the statement is executed later will be the definition of the view at the time it was prepared. This is true even if the view definition is changed after the statement is prepared and before it is executed. Example:CREATE VIEW v AS SELECT RAND(); PREPARE s FROM 'SELECT * FROM v'; ALTER VIEW v AS SELECT NOW(); EXECUTE s;
The result returned by the
EXECUTEstatement is a random number, not the current date and time.
With regard to view updatability, the overall goal for views is
that if any view is theoretically updatable, it should be
updatable in practice. This includes views that have
UNION in their definition.
Currently, not all views that are theoretically updatable can be
updated. The initial view implementation was deliberately written
this way to get usable, updatable views into MySQL as quickly as
possible. Many theoretically updatable views can be updated now,
but limitations still exist:
Updatable views with subqueries anywhere other than in the
WHEREclause. Some views that have subqueries in theSELECTlist may be updatable.You cannot use
UPDATEto update more than one underlying table of a view that is defined as a join.You cannot use
DELETEto update a view that is defined as a join.
There exists a shortcoming with the current implementation of
views. If a user is granted the basic privileges necessary to
create a view (the CREATE VIEW and
SELECT privileges), that user will
be unable to call SHOW CREATE VIEW
on that object unless the user is also granted the
SHOW VIEW privilege.
That shortcoming can lead to problems backing up a database with mysqldump, which may fail due to insufficient privileges. This problem is described in Bug#22062.
The workaround to the problem is for the administrator to manually
grant the SHOW VIEW privilege to
users who are granted CREATE VIEW,
since MySQL doesn't grant it implicitly when views are created.
Views do not have indexes, so index hints do not apply. Use of index hints when selecting from a view is disallowed.
SHOW CREATE VIEW displays view
definitions using an AS
clause for each
column. If a column is created from an expression, the default
alias is the expression text, which can be quite long. Aliases for
column names in alias_nameCREATE VIEW
statements are checked against the maximum column length of 64
characters (not the maximum alias length of 256 characters). As a
result, views created from the output of SHOW
CREATE VIEW fail if any column alias exceeds 64
characters. This can cause problems in the following circumstances
for views with too-long aliases:
View definitions fail to replicate to newer slaves that enforce the column-length restriction.
Dump files created with mysqldump cannot be loaded into servers that enforce the column-length restriction.
A workaround for either problem is the modify each problematic
view definition to use aliases that provide shorter column names.
Then the view will replicate properly, and can be dumped and
reloaded without causing an error. To modify the definition, drop
and create the view again with DROP
VIEW and CREATE VIEW, or
replace the definition with
CREATE OR REPLACE
VIEW.
For problems that occur when reloading view definitions in dump
files, another workaround is to edit the dump file to modify its
CREATE VIEW statements. However,
this does not change the original view definitions, which may
cause problems for subsequent dump operations.
XA transaction support is limited to the InnoDB
storage engine.
For “external XA,” a MySQL server acts as a Resource
Manager and client programs act as Transaction Managers. For
“Internal XA”, storage engines within a MySQL server
act as RMs, and the server itself acts as a TM. Internal XA
support is limited by the capabilities of individual storage
engines. Internal XA is required for handling XA transactions that
involve more than one storage engine. The implementation of
internal XA requires that a storage engine support two-phase
commit at the table handler level, and currently this is true only
for InnoDB.
For XA
START, the JOIN and
RESUME clauses are not supported.
For XA
END, the SUSPEND [FOR MIGRATE] clause
is not supported.
The requirement that the bqual part of
the xid value be different for each XA
transaction within a global transaction is a limitation of the
current MySQL XA implementation. It is not part of the XA
specification.
If an XA transaction has reached the PREPARED
state and the MySQL server is killed (for example, with
kill -9 on Unix) or shuts down abnormally, the
transaction can be continued after the server restarts. However,
if the client reconnects and commits the transaction, the
transaction will be absent from the binary log even though it has
been committed. This means the data and the binary log have gone
out of synchrony. An implication is that XA cannot be used safely
together with replication.
It is possible that the server will roll back a pending XA
transaction, even one that has reached the
PREPARED state. This happens if a client
connection terminates and the server continues to run, or if
clients are connected and the server shuts down gracefully. (In
the latter case, the server marks each connection to be
terminated, and then rolls back the PREPARED XA
transaction associated with it.) It should be possible to commit
or roll back a PREPARED XA transaction, but
this cannot be done without changes to the binary logging
mechanism.
Identifiers are stored in
mysqldatabase tables (user,db, and so forth) usingutf8, but identifiers can contain only characters in the Basic Multilingual Plane (BMP). Supplementary characters are not allowed in identifiers.The
ucs2character sets has the following restrictions:It cannot be used as a client character set, which means that it does not work for
SET NAMESorSET CHARACTER SET. (See Section 9.1.4, “Connection Character Sets and Collations”.)It is currently not possible to use
LOAD DATA INFILEto load data files that use this character set.FULLTEXTindexes cannot be created on a column that this character set. However, you can performIN BOOLEAN MODEsearches on the column without an index.
The
REGEXPandRLIKEoperators work in byte-wise fashion, so they are not multi-byte safe and may produce unexpected results with multi-byte character sets. In addition, these operators compare characters by their byte values and accented characters may not compare as equal even if a given collation treats them as equal.
This section lists current limits in MySQL 5.4.
The maximum number of tables that can be referenced in a single join is 61. This also applies to the number of tables that can be referenced in the definition of a view.
There is a hard limit of 4096 columns per table, but the effective maximum may be less for a given table. The exact limit depends on several interacting factors, listed in the following discussion.
Every table has a maximum row size of 65,535 bytes. This maximum applies to all storage engines, but a given engine might have additional constraints that result in a lower effective maximum row size.
The maximum row size constrains the number of columns because the total width of all columns cannot exceed this size. For example,
utf8characters require up to three bytes per character, so for aCHAR(255) CHARACTER SET utf8column, the server must allocate 255 × 3 = 765 bytes per value. Consequently, a table cannot contain more than 65,535 / 765 = 85 such columns.Storage for variable-length columns includes length bytes, which are assessed against the row size. For example, a
VARCHAR(255) CHARACTER SET utf8column takes two bytes to store the length of the value, so each value can take up to 767 bytes.BLOBandTEXTcolumns count from one to four plus eight bytes each toward the row-size limit because their contents are stored separately.Declaring columns
NULLcan reduce the maximum number of columns allowed.NULLcolumns require additional space in the row to record whether or not their values areNULL.For
MyISAMtables, eachNULLcolumn takes one bit extra, rounded up to the nearest byte. The maximum row length in bytes can be calculated as follows:row length = 1 + (sum of column lengths) + (number of NULL columns+delete_flag+ 7)/8 + (number of variable-length columns)delete_flagis 1 for tables with static row format. Static tables use a bit in the row record for a flag that indicates whether the row has been deleted.delete_flagis 0 for dynamic tables because the flag is stored in the dynamic row header.These calculations do not apply for
InnoDBtables, for which storage size is no different forNULLcolumns than forNOT NULLcolumns.The following statement to create table
t1succeeds because the columns require 32,765 + 2 bytes and 32,766 + 2 bytes, which falls within the maximum row size of 65,535 bytes:mysql>
CREATE TABLE t1->(c1 VARCHAR(32765) NOT NULL, c2 VARCHAR(32766) NOT NULL);Query OK, 0 rows affected (0.01 sec)The following statement to create table
t2fails because the columns areNULLand require additional space that causes the row size to exceed 65,535 bytes:mysql>
CREATE TABLE t2->(c1 VARCHAR(32765) NULL, c2 VARCHAR(32766) NULL);ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. You have to change some columns to TEXT or BLOBsEach table has an
.frmfile that contains the table definition. The.frmfile size limit is fixed at 64KB. If a table definition reaches this size, no more columns can be added. The expression that checks information to be stored in the.frmfile against the limit looks like this:if (info_length+(ulong) create_fields.elements*FCOMP+288+ n_length+int_length+com_length > 65535L || int_count > 255)The relevant factors in this expression are:
info_lengthis space needed for “screens.” This is related to MySQL's Unireg heritage.create_fields.elementsis the number of columns.FCOMPis 17.n_lengthis the total length of all column names, including one byte per name as a separator.int_lengthis related to the list of values for SET and ENUM columns.com_lengthis the total length of column and table comments.
Thus, using long column names can reduce the maximum number of columns, as can the inclusion of
ENUMorSETcolumns, or use of column or table comments.Individual storage engines might impose additional restrictions that limit table column count. Examples:
InnoDBallows no more than 1000 columns.InnoDBrestricts row size to something less than half a database page (approximately 8000 bytes), not includingVARBINARY,VARCHAR,BLOB, orTEXTcolumns.Different
InnoDBstorage formats (COMPRESSED,REDUNDANT) use different amounts of page header and trailer data, which affects the amount of storage available for rows.
The following limitations apply only to the Windows platform:
The number of open file descriptors on Windows is limited to a maximum of 2048, which may limit the ability to open a large number of tables simultaneously. This limit is due to the compatibility functions used to open files on Windows that use the POSIX compatibility layer.
This limitation will also cause problems if you try to set
open_files_limitto a value greater than the 2048 file limit.On Windows 32-bit platforms it is not possible to use more than 2GB of RAM within a single process, including MySQL. This is because the physical address limit on Windows 32-bit is 4GB and the default setting within Windows is to split the virtual address space between kernel (2GB) and user/applications (2GB).
To use more memory than this you will need to use a 64-bit version of Windows.
When using
MyISAMtables, you cannot use aliases within Windows link to the data files on another volume and then link back to the main MySQLdatadirlocation.This facility is often used to move the data and index files to a RAID or other fast solution, while retaining the main
.FRMfiles in the default data directory configured with thedatadiroption.The timers within MySQL used on Windows are of a lower precision than the timers used on Linux. For most situations you may not notice a difference, but the delay implied by a call to
SLEEP()on Windows and Linux may differ slightly due to the differences in precision.There is no 64-bit OLEDB Provider for ODBC (MSDASQL) in any 64-bit Windows operating system up to and including Windows Vista. In practical terms this means that you can't use the MySQL ODBC driver from ADO and other users of OLEDB.
