21

Assume that the following query is issued to a MySQL database:

SELECT * FROM table_name;

Note that no ORDER BY clause is given.

My question is:

Does MySQL give any guarantees to which order the result set rows will be given?

More specifically, can I assume that the rows will be returned in insertion order?, that is the same order in which the rows were inserted into the table.

Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
knorv
  • 49,059
  • 74
  • 210
  • 294
  • 1
    Duplicate: http://stackoverflow.com/questions/1793147/sql-best-practice-to-deal-with-default-sort-order – OMG Ponies Dec 22 '09 at 22:58
  • 1
    OMG Ponies: Thanks for the link - it contains some very useful answers. I wouldn't consider that question an exact duplicate since it is very general, whereas my question is MySQL specific. – knorv Dec 22 '09 at 23:23
  • See also: http://stackoverflow.com/questions/899514/default-row-ordering-for-select-query-in-oracle (Oracle, MySQL and basically all RDBMSs should be same in regards to default order), http://stackoverflow.com/questions/1807079/how-to-reverse-the-default-ordering-in-mysql – outis Dec 22 '09 at 23:31
  • Does this answer your question? [SQL best practice to deal with default sort order](https://stackoverflow.com/questions/1793147/sql-best-practice-to-deal-with-default-sort-order) – philipxy Mar 30 '22 at 12:24

6 Answers6

33

No, there are no guarantees. Unless you specify an order using an ORDER BY clause, the order is totally dependent on internal implementation details. I.e. whatever is most convenient for the RDBMS engine.

In practice, the rows might be returned in their original insertion order (or more accurately the order the rows exist in physical storage), but you should not depend on this. If you port your app to another brand of RDBMS, or even if you upgrade to a newer version of MySQL that may implement storage differently, the rows could come back in some other order.

The latter point is true for any SQL-compliant RDBMS.


Update: in practice, InnoDB returns rows by default in the order it reads them from the index, so the order depends on which index is used by the optimizer. Depending on the columns and conditions you have in your query, it may choose a different index.

Here's a demonstration using InnoDB: I create a table and insert rows such that the values I insert are the opposite order of the primary key.

CREATE TABLE foo (id SERIAL PRIMARY KEY, bar CHAR(10), baz CHAR(10), KEY(bar));

INSERT INTO foo (bar, baz) VALUES
  ('test5', 'test5'), ('test5', 'test5'),
  ('test4', 'test4'), ('test4', 'test4'), 
  ('test3', 'test3'), ('test3', 'test3'), 
  ('test2', 'test2'), ('test2', 'test2'), 
  ('test1', 'test1'), ('test1', 'test1');

By default, if no index is used, the rows are returned in primary key order, because the are read from the clustered index (the primary key).

select * from foo;
+----+-------+-------+
| id | bar   | baz   |
+----+-------+-------+
|  1 | test5 | test5 |
|  2 | test5 | test5 |
|  3 | test4 | test4 |
|  4 | test4 | test4 |
|  5 | test3 | test3 |
....

But if we use a query that uses an index, it reads the rows in the order of that index. Notice when there are ties, the tied index entries are stored in order of primary key, ascending. That's the order they are returned.

select * from foo where bar between 'test2' and 'test4';
+----+-------+-------+
| id | bar   | baz   |
+----+-------+-------+
|  7 | test2 | test2 |
|  8 | test2 | test2 |
|  5 | test3 | test3 |
|  6 | test3 | test3 |
|  3 | test4 | test4 |
|  4 | test4 | test4 |
+----+-------+-------+

Using a different storage engine means a different implementation, and the default order may be different. In the case of MyISAM, rows are stored in the order they were created.

Here's a demonstration of what I mean:

CREATE TABLE foo (id SERIAL PRIMARY KEY, bar CHAR(10));

-- create rows with id 1 through 10
INSERT INTO foo (bar) VALUES
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing'), 
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing');

DELETE FROM foo WHERE id BETWEEN 4 AND 7;

+----+---------+
| id | bar     |
+----+---------+
|  1 | testing |
|  2 | testing |
|  3 | testing |
|  8 | testing |
|  9 | testing |
| 10 | testing |
+----+---------+

So now we have six rows. The storage at this point contains a gap between rows 3 and 8, left after deleting the middle rows. Deleting rows does not defragment these gaps.

-- create rows with id 11 through 20 
INSERT INTO foo (bar) VALUES
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing'), 
  ('testing'), ('testing'), ('testing'), ('testing'), ('testing');

SELECT * FROM foo;

+----+---------+
| id | bar     |
+----+---------+
|  1 | testing |
|  2 | testing |
|  3 | testing |
| 14 | testing |
| 13 | testing |
| 12 | testing |
| 11 | testing |
|  8 | testing |
|  9 | testing |
| 10 | testing |
| 15 | testing |
| 16 | testing |
| 17 | testing |
| 18 | testing |
| 19 | testing |
| 20 | testing |
+----+---------+

Notice how MySQL has re-used the spaces opened by deleting rows, before appending new rows to the end of the table. Also notice that rows 11 through 14 were inserted in these spaces in reverse order, filling from the end backwards.

Therefore the order the rows are stored is not exactly the order in which they were inserted.

Bill Karwin
  • 538,548
  • 86
  • 673
  • 828
  • What`s version of your MySQL. My mysql DBMS version is 5.6.16, for osx10.9 (x86_64). The result is very different from yours. – wanghao Aug 21 '15 at 02:45
  • Click http://7ktwa5.com1.z0.glb.clouddn.com/the_sort_of_mysql.png for more details. – wanghao Aug 21 '15 at 02:46
  • 1
    @wanghao, I wrote this answer in 2009, when the default storage engine was MyISAM. In MySQL 5.6, the default storage engine is InnoDB, which always stores rows in primary key order. Try the experiment with a MyISAM table. – Bill Karwin Aug 21 '15 at 17:38
  • @BillKarwin, then I use MyISAM, it works, thank you! – wanghao Aug 25 '15 at 00:06
  • @BillKarwin InnoDB may store things in primary key order, but it sure doesn't hand them to me in that order when I omit `ORDER BY`. I am testing a query with a join that runs MUCH faster without the ORDER BY clause I had hoped that I could speed up my results by changing my primary key. But it's not working with the primary key I have now anyway. – Buttle Butkus Oct 21 '15 at 22:41
  • 1
    @ButtleButkus, the data is returned in the order of the index that it uses to traverse the data. Refer to EXPLAIN to find out which index it's using for the first table. – Bill Karwin Oct 22 '15 at 00:03
  • If have query: `INSERT INTO table (`value`) VALUES ("first"), ("second"), ("third")`. Can i be sure that "first" would be inserted in first row, "second" in next row and "third" after the "second"? When tested myself, yes inserts in the same order as in query. But can i be 100% sure that always inserts in the same order as in query? – Andris Mar 14 '23 at 04:46
  • 1
    @Andris, If it's that important, then execute INSERT one row at a time. – Bill Karwin Mar 14 '23 at 05:38
  • @BillKarwin Thank you for information. So, seems after each `INSERT` must get and "save" as variable `lastInsertId`. Another idea was at first get `MAX(Id)` and then insert (`Id`, `Value`) VALUES (`MAX(Id)`+1, "first"), (`MAX(Id)`+2, "second") and so on... – Andris Mar 14 '23 at 05:52
  • 1
    @Andris, Okay, you are concerned about whether auto-increment id's are predictable when you do multi-row INSERT. That was not clear from your earlier comment. I answer that question here: https://stackoverflow.com/questions/55007957/am-i-guaranteed-to-get-consecutive-ids-with-a-single-insert-statement-in-mysql/55009330#55009330 – Bill Karwin Mar 14 '23 at 16:52
5

Per this thread, default sort is insert order for MyISAM, and primary key ascending for InnoDB. But I don't think that's a guarantee, just how it's known to work.

Kaleb Brasee
  • 51,193
  • 8
  • 108
  • 113
  • Results will definitely not be in those orders if you are doing deletes as well as inserts in those tables. @BillKarwin has a good explanation of why above. – Loren_ Jul 21 '15 at 18:45
5

No, you cannot.

Sometimes MySQL will perform select queries with keys you don't expect. Consider this table:

CREATE TABLE `user_permissions` (
  `permId` int(5) unsigned NOT NULL AUTO_INCREMENT,
  `permKey` varchar(16) NOT NULL,
  `permDesc` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`permId`),
  KEY `key_lookup` (`permKey`,`permId`,`permDesc`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

MySQL will almost always use the key_lookup key to do any select operation on this table; since permKey is the first field, it will usually end up "sorted" by this key (which appears alphabetical, but isn't exactly).

Without an ORDER BY clause, MySQL (and most/all RDBMS engines) will try to get the data just as it's stored and just as fast as possible.

Dereleased
  • 9,939
  • 3
  • 35
  • 51
3

From Retrieving Data Using the MySQL SELECT Statement : The SELECT Statement

The data displayed is not ordered. Usually records are retrieved in the same order in which they were inserted into the database

Yes, as per the comment

Although records are normally retrieved in the order in which they are inserted into the database, you cannot rely on a particular order being preserved. If your database is backed up and restored, or if a maintenance operation is performed on the database, MySQL might alter the order in which records are stored internally.

Adriaan Stander
  • 162,879
  • 31
  • 289
  • 284
  • 2
    Annnnd... right after that: "Although records are normally retrieved in the order in which they are inserted into the database, you cannot rely on a particular order being preserved." You can never rely on this because as soon as a data page is full, rows are moved around. – womp Dec 22 '09 at 22:43
  • That is true, I do aggree with the fact that without an orderby, you are not sure what you get back. – Adriaan Stander Dec 22 '09 at 22:46
1

No, definitely not. Depending on the database engine you're using (ISAM or InnoDB), table structure will generally be some kind of b-tree to allow for faster searching through rows. This will have nothing to do with insertion order, and more to do with how the database constructs an index based on the primary key (or in the case of no key, how a table heap is stored).

womp
  • 115,835
  • 26
  • 236
  • 269
0

the results in mysql 5.6 are not select by default in inserting order, you can do updates etc and it returs the query in any order it likes

Amir Buzo
  • 69
  • 9