MySQL Differences Compared to SQL-92

We try to make MySQL Server follow the ANSI SQL standard (SQL-92/SQL-99) and the ODBC SQL standard, but MySQL Server performs operations differently in some cases:

Subqueries

MySQL Version 4.1 supports subqueries and derived tables. A subquery is a SELECT statement nested within another statement. A derived table (an unnamed view) is a subquery in the FROM clause of another statement. See Subqueries.

For MySQL versions older than 4.1, most subqueries can be rewritten using joins or other methods. See Rewriting subqueries for examples that show how to do this.

SELECT INTO TABLE

MySQL Server doesn't support the Sybase SQL extension: SELECT ... INTO TABLE .... Instead, MySQL Server supports the SQL-99 syntax INSERT INTO ... SELECT ..., which is basically the same thing. See INSERT SELECT.

INSERT INTO tblTemp2 (fldID)
       SELECT tblTemp1.fldOrder_ID
       FROM tblTemp1 WHERE tblTemp1.fldOrder_ID > 100;

Alternatively, you can use SELECT INTO OUTFILE ... or CREATE TABLE ... SELECT.

From version 5.0, MySQL supports SELECT ... INTO with user variables. The same syntax may also be used inside stored procedures using cursors and local variables. See SELECT INTO Statement.

Transactions and Atomic Operations

MySQL Server (version 3.23-max and all versions 4.0 and above) supports transactions with the InnoDB and BDB transactional storage engines. InnoDB provides full ACID compliance. See Table types.

The other non-transactional storage engines in MySQL Server (such as MyISAM) follow a different paradigm for data integrity called ``Atomic Operations.'' In transactional terms, MyISAM tables effectively always operate in AUTOCOMMIT=1 mode. Atomic operations often offer comparable integrity with higher performance.

With MySQL Server supporting both paradigms, you can decide whether your applications are best served by the speed of atomic operations or the use of transactional features. This choice can be made on a per-table basis.

As noted, the trade off for transactional vs. non-transactional table types lies mostly in performance. Transactional tables have significantly higher memory and diskspace requirements, and more CPU overhead. On the other hand, transactional table types such as InnoDB also offer many significant features. MySQL Server's modular design allows the concurrent use of different storage engines to suit different requirements and deliver optimum performance in all situations.

But how does one use the features of MySQL Server to maintain rigorous integrity even with the non-transactional MyISAM tables, and how do these features compare with the transactional table types?

  1. If your applications are written in a way that is dependent on being able to call ROLLBACK rather than COMMIT in critical situations, transactions are more convenient. Transactions also ensure that unfinished updates or corrupting activities are not committed to the database; the server is given the opportunity to do an automatic rollback and your database is saved.

    If you use non-transactional tables, MySQL Server in almost all cases allows you to resolve potential problems by including simple checks before updates and by running simple scripts that check the databases for inconsistencies and automatically repair or warn if such an inconsistency occurs. Note that just by using the MySQL log or even adding one extra log, one can normally fix tables perfectly with no data integrity loss.

  2. More often than not, critical transactional updates can be rewritten to be atomic. Generally speaking, all integrity problems that transactions solve can be done with LOCK TABLES or atomic updates, ensuring that you never will get an automatic abort from the server, which is a common problem with transactional database systems.

  3. Even a transactional system can lose data if the server goes down. The difference between different systems lies in just how small the time-lap is where they could lose data. No system is 100% secure, only ``secure enough.'' Even Oracle, reputed to be the safest of transactional database systems, is reported to sometimes lose data in such situations.

    To be safe with MySQL Server, whether using transactional tables or not, you only need to have backups and have binary logging turned on. With this you can recover from any situation that you could with any other transactional database system. It is always good to have backups, independent of which database system you use.

The transactional paradigm has its benefits and its drawbacks. Many users and application developers depend on the ease with which they can code around problems where an abort appears to be, or is necessary. However, even if you are new to the atomic operations paradigm, or more familiar with transactions, do consider the speed benefit that non-transactional tables can offer on the order of three to five times the speed of the fastest and most optimally tuned transactional tables.

In situations where integrity is of highest importance, MySQL Server offers transaction-level reliability and integrity even for non-transactional tables. If you lock tables with LOCK TABLES, all updates will stall until any integrity checks are made. If you obtain a READ LOCAL lock (as opposed to a write lock) for a table that allows concurrent inserts at the end of the table, reads are allowed, as are inserts by other clients. The new inserted records will not be seen by the client that has the read lock until it releases the lock. With INSERT DELAYED you can queue inserts into a local queue, until the locks are released, without having the client wait for the insert to complete. See INSERT DELAYED.

``Atomic,'' in the sense that we mean it, is nothing magical. It only means that you can be sure that while each specific update is running, no other user can interfere with it, and there will never be an automatic rollback (which can happen with transactional tables if you are not very careful). MySQL Server also guarantees that there will not be any dirty reads.

Following are some techniques for working with non-transactional tables:

  • Loops that need transactions normally can be coded with the help of LOCK TABLES, and you don't need cursors to update records on the fly.

  • To avoid using ROLLBACK, you can use the following strategy:

    1. Use LOCK TABLES ... to lock all the tables you want to access.

    2. Test the conditions that must be true before performing the update.

    3. Update if everything is okay.

    4. Use UNLOCK TABLES to release your locks.

    This is usually a much faster method than using transactions with possible rollbacks, although not always. The only situation this solution doesn't handle is when someone kills the threads in the middle of an update. In this case, all locks will be released but some of the updates may not have been executed.

  • You can also use functions to update records in a single operation. You can get a very efficient application by using the following techniques:

    • Modify fields relative to their current value.

    • Update only those fields that actually have changed.

    For example, when we are doing updates to some customer information, we update only the customer data that has changed and test only that none of the changed data, or data that depends on the changed data, has changed compared to the original row. The test for changed data is done with the WHERE clause in the UPDATE statement. If the record wasn't updated, we give the client a message: ''Some of the data you have changed has been changed by another user.'' Then we show the old row versus the new row in a window, so the user can decide which version of the customer record he should use.

    This gives us something that is similar to column locking but is actually even better because we only update some of the columns, using values that are relative to their current values. This means that typical UPDATE statements look something like these:

      UPDATE tablename SET pay_back=pay_back+125;
      UPDATE customer
        SET
          customer_date='current_date',
          address='new address',
          phone='new phone',
          money_he_owes_us=money_he_owes_us-125
        WHERE
          customer_id=id AND address='old address' AND phone='old phone';
      

    As you can see, this is very efficient and works even if another client has changed the values in the pay_back or money_he_owes_us columns.

  • In many cases, users have wanted LOCK TABLES and/or ROLLBACK for the purpose of managing unique identifiers. This can be handled much more efficiently without locking or rolling back by using an AUTO_INCREMENT column and either the SQL function LAST_INSERT_ID() or the C API function mysql_insert_id(). See Information functions. See mysql_insert_id().

    You can generally code around the need for row-level locking. Some situations really do need it, and InnoDB tables support row-level locking. With MyISAM tables, you can use a flag column in the table and do something like the following:

      UPDATE tbl_name SET row_flag=1 WHERE id=ID;
      

    MySQL returns 1 for the number of affected rows if the row was found and row_flag wasn't already 1 in the original row.

    You can think of it as though MySQL Server changed the preceding query to:

      UPDATE tbl_name SET row_flag=1 WHERE id=ID AND row_flag <> 1;
      

Stored Procedures and Triggers

Stored procedures are implemented in MySQL version 5.0. See Stored Procedures.

Triggers are scheduled for implementation in MySQL version 5.1. A trigger is effectively a type of stored procedure, one that is invoked when a particular event occurs. For example, you could set up a stored procedure that is triggered each time a record is deleted from a transactional table and that stored procedure automatically deletes the corresponding customer from a customer table when all their transactions are deleted.

Foreign Keys

In MySQL Server 3.23.44 and up, the InnoDB storage engine supports checking of foreign key constraints, including CASCADE, ON DELETE, and ON UPDATE. See InnoDB foreign key constraints.

For storage engines other than InnoDB, MySQL Server parses the FOREIGN KEY syntax in CREATE TABLE statements, but does not use or store it. In the future, the implementation will be extended to store this information in the table specification file so that it may be retrieved by mysqldump and ODBC. At a later stage, foreign key constraints will be implemented for MyISAM tables as well.

Foreign key enforcement offers several benefits to database developers:

  • Assuming proper design of the relationships, foreign key constraints make it more difficult for a programmer to introduce an inconsistency into the database.

  • Centralized checking of constraints by the database server makes it unnecessary to perform these checks on the application side. This eliminates the possibility that different applications may not all check the constraints in the same way.

  • Using cascading updates and deletes can simplify the application code.

  • Properly designed foreign key rules aid in documenting relationships between tables.

Do keep in mind that these benefits come at the cost of additional overhead for the database server to perform the necessary checks. Additional checking by the server affects performance, which for some applications may be sufficiently undesirable as to be avoided if possible. (Some major commercial applications have coded the foreign-key logic at the application level for this reason.)

MySQL gives database developers the choice of which approach to use. If you don't need foreign keys and want to avoid the overhead associated with enforcing referential integrity, you can choose another table type instead, such as MyISAM. (For example, the MyISAM storage engine offers very fast performance for applications that perform only INSERT and SELECT operations, because the inserts can be performed concurrently with retrievals. See Table locking.)

If you choose not to take advantage of referential integrity checks, keep the following considerations in mind:

  • In the absence of server-side foreign key relationship checking, the application itself must handle relationship issues. For example, it must take care to insert rows into tables in the proper order, and to avoid creating orphaned child records. It must also be able to recover from errors that occur in the middle of multiple-record insert operations.

  • If ON DELETE is the only referential integrity capability an application needs, note that as of MySQL Server 4.0, you can use multiple-table DELETE statements to delete rows from many tables with a single statement. See DELETE.

  • A workaround for the lack of ON DELETE is to add the appropriate DELETE statement to your application when you delete records from a table that has a foreign key. In practice, this is often as quick as using foreign keys, and is more portable.

Be aware that the use of foreign keys can in some instances lead to problems:

  • Foreign key support addresses many referential integrity issues, but it is still necessary to design key relationships carefully to avoid circular rules or incorrect combinations of cascading deletes.

  • It is not uncommon for a DBA to create a topology of relationships that makes it difficult to restore individual tables from a backup. (MySQL alleviates this difficulty by allowing you to temporarily disable foreign key checks when reloading a table that depends on other tables. See InnoDB foreign key constraints. As of MySQL 4.1.1, mysqldump generates dump files that take advantage of this capability automatically when reloaded.)

Note that foreign keys in SQL are used to check and enforce referential integrity, not to join tables. If you want to get results from multiple tables from a SELECT statement, you do this by performing a join between them:

SELECT * FROM table1,table2 WHERE table1.id = table2.id;

See JOIN. See example-Foreign keys.

The FOREIGN KEY syntax without ON DELETE ... is often used by ODBC applications to produce automatic WHERE clauses.

Views

Views are currently being implemented, and will appear in the 5.0 or 5.1 version of MySQL Server. Unnamed views (derived tables, a subquery in the FROM clause of a SELECT) are already implemented in version 4.1.

Historically, MySQL Server has been most used in applications and on web systems where the application writer has full control over database usage. Usage has shifted over time, and so we find that an increasing number of users now regard views as an important feature.

Views are useful for allowing users to access a set of relations (tables) as if it were a single table, and limiting their access to just that. Views can also be used to restrict access to rows (a subset of a particular table). One does not require views to restrict access to columns, as MySQL Server has a sophisticated privilege system. See Privilege system.

Many DBMS don't allow updates to a view. Instead, you have to perform the updates on the individual tables. In designing an implementation of views, our goal, as much as is possible within the confines of SQL, is full compliance with ``Codd's Rule #6'' for relational database systems: All views that are theoretically updatable, should in practice also be updatable.

-- as the Start of a Comment

Some other SQL databases use -- to start comments. MySQL Server uses # as the start comment character. You can also use the C comment style /* this is a comment */ with MySQL Server. See Comments.

MySQL Server Version 3.23.3 and above support the -- comment style, provided the comment is followed by a space (or by a control character such as a newline). The requirement for a space is to prevent problems with automatically generated SQL queries that have used something like the following code, where we automatically insert the value of the payment for !payment!:

UPDATE tbl_name SET credit=credit-!payment!

Think about what happens if the value of payment is a negative value such as -1:

UPDATE tbl_name SET credit=credit--1

credit--1 is a legal expression in SQL, but if -- is interpreted as the start of a comment, part of the expression is discarded. The result is a statement that has a completely different meaning than intended:

UPDATE tbl_name SET credit=credit

The statement produces no change in value at all! This illustrates that allowing comments to start with -- can have serious consequences.

Using our implementation of this method of commenting in MySQL Server Version 3.23.3 and up, credit--1 is actually safe.

Another safe feature is that the mysql command-line client removes all lines that start with --.

The following information is relevant only if you are running a MySQL version earlier than 3.23.3:

If you have an SQL program in a text file that contains -- comments, you should use the replace utility as follows to convert the comments to use # characters:

shell> replace " --" " #" < text-file-with-funny-comments.sql \
         | mysql database

instead of the usual:

shell> mysql database < text-file-with-funny-comments.sql

You can also edit the command file ``in place'' to change the -- comments to # comments:

shell> replace " --" " #" -- text-file-with-funny-comments.sql

Change them back with this command:

shell> replace " #" " --" -- text-file-with-funny-comments.sql