由于数据无序,导致检索数据时都是按照存储时的物理顺序进行访问,如此检索得到的数据���都是随机而不保证任何顺序的,除非指定了ORDER BY子句。而使用ORDER BY查询得到的结果,它因为有序而不满足集合的概念。实际上ORDER BY生成的是一个游标结果。了解SQL的人,都知道能不用游标就尽量不用游标,因为它的效率相比符合集合概念的SQL语句来说,要慢很多个数量级。但也不能一棍子将其打死,因为有时候使用游标确实能比较容易达到查询目标。
在SQL中没有使用ORDER BY时,有不少子句的返回结果(虚拟表)都是随机的,因为实在没办法去保证顺序,但却又要求返回数据。例如直接进行SELECT * from t; ,再例如TOP/LIMIT子句。
纵观整个SQL的各个环节,不难发现很多时候获取随机行数据是不应该的,因为这种不确定性,让我们操作数据时显得更出乎意料、更危险。因此,除非不得不显示随机数据,标准SQL都会通过一些手段让获取随机数据的行为失败,而且在可能获取随机数据的时候,一般都会给出相关的建议和提示。
MySQL、mariadb之所以和sql server、oracle的语法相差那么大,归根结底就是对待关系型数据库的范式要求和随机数据的态度不同。MySQL、mariadb总是"偷奸耍滑",在本无法满足关系型数据库范式的时候,它们总是挑选一个随机单行数据出来,让返回结果满足范式要求,最典型的就是group by的处理方式。不过MySQL从5.7.5版本开始,已经逐渐走向规范化了。
这里并非是要否认mysql、mariadb的设计模式,正所谓每个数据库系统都有自己对标准SQL的扩展方式,MySQL只是走了一条和标准SQL不同的路而已。而且关系模型的范式本就是人为定义的,为何不能违反呢?甚至可以说,表所满足的范式越强,检索表时的性能越低,nosql就没有关系模型的范式要求。
在后文,将在多处分析标准SQL为什么不允许某些语法,同时还会提到MySQL和mariadb是如何"偷奸耍滑"的。
1.6 关于TOP(或LIMIT)和ORDER BYTOP和LIMIT是限制输出行数量,它们挑选数据行时是随机的(根据物理访问顺序),所以得到的结果也是随机的。因此,建议TOP/LIMIT和ORDER BY一起使用。但即使如此,仍是不安全的。例如,ORDER BY的列中有重复值,那么TOP/LIMIT的时候如何决定获取哪些行呢?见如下LIMIT的示例(TOP也一样):
MariaDB [test]> select * from Student order by age;
+------+----------+------+--------+
| sid | name | age | class |
+------+----------+------+--------+
| 6 | zhaoliu | 19 | Java |
| 4 | lisi | 20 | C# |
| 8 | sunba | 20 | C++ |
| 3 | zhangsan | 21 | Java |
| 5 | wangwu | 21 | Python |
| 1 | chenyi | 22 | Java |
| 7 | qianqi | 22 | C |
| 2 | huanger | 23 | Python |
| 9 | yangjiu | 24 | Java |
+------+----------+------+--------+
MariaDB [test]> select * from Student order by age limit 9;
+------+----------+------+--------+
| sid | name | age | class |
+------+----------+------+--------+
| 6 | zhaoliu | 19 | Java |
| 4 | lisi | 20 | C# |
| 8 | sunba | 20 | C++ |
| 3 | zhangsan | 21 | Java |
| 5 | wangwu | 21 | Python |
| 1 | chenyi | 22 | Java |
| 7 | qianqi | 22 | C |
| 2 | huanger | 23 | Python |
| 9 | yangjiu | 24 | Java |
+------+----------+------+--------+
从两次查询结果中看到,即使都是对age进行升序排列,但age=20的两行前后顺序不一致,age=22的行顺序也不一致。