我有一个名为links
的SQL-MyIsam表,其结构如下
| field | type | null | predefined | extra |
|------------|--------------|------|------------------|----------------|
| id | int(11) | no | none | auto_increment |
| link | varcar(2083) | no | none | none |
| created_at | timestamp | no | curret_timestamp | none |
| origin | varcar(100) | no | none | none |
我的插入语句是
public function createLink($user_id, $link, $origin) {
$stmt = $this->conn->prepare("INSERT INTO links(link, origin) VALUES(?,?)");
$stmt->bind_param("ss", $link, $origin);
$result = $stmt->execute();
$stmt->close();
if ($result) {
// link row created
// now assign the link to user
$new_link_id = $this->conn->insert_id;
$res = $this->createUserLink($user_id, $new_link_id);
if ($res) {
// link created successfully
return $new_link_id;
} else {
// user_link failed to create
return NULL;
}
} else {
// link failed to create
return NULL;
}
}
不幸的是,有时候我会出现一种意想不到的行为,而这种行为并不能完全复制。
如您所见,在286和293之间插入了ID为301和304的行,以及ID为300的行在298和296之间。
由于id是自动增量,我本来希望找到从较小值到较高值的所有序列。
这对我的应用程序来说很糟糕,因为我需要遵循创建的时间顺序并且每当我查询数据库以获取所有链接时都会遵循
public function getAllUserLinks($user_id) {
$stmt = $this->conn->prepare("SELECT l.* FROM links l, users_links ul WHERE l.id = ul.link_id AND ul.user_id = ?");
$stmt->bind_param("i", $user_id);
$stmt->execute();
$links = $stmt->get_result();
$stmt->close();
return $links;
}
我知道我可以在我的查询中添加ORDER BY...
,但这会进一步降低速度。
此外,新链接应该作为表格的最后一行添加,而不是在中间,对吧?!
答案 0 :(得分:0)
所以你看到的物理顺序将归结为你的聚集索引,如果你还没有定义,那么MySQL会为你做这些,来自InnoDB docs here:
如果表没有PRIMARY KEY或合适的UNIQUE索引,InnoDB会在包含行ID值的合成列内部生成隐藏聚簇索引。行按InnoDB分配给此类表中的行的ID排序。行ID是一个6字节的字段,随着新行的插入而单调增加。因此,按行ID排序的行在物理上按插入顺序排列。
我假设您正在使用InnoDB,但MyISAM也会使用聚集索引来确定物理顺序。关于聚簇索引的更多信息here。
下面的评论是正确的,说聚集索引是数据的存储方式,严格来说不是数据的检索方式。在实践中,如果您没有指定ORDER BY,您很有可能会找到按物理顺序返回的数据。
我试图解释为什么提问者可能会看到他的顺序,但我并不是说这应该被依赖,没有ORDER BY就没有关于数据顺序的保证。来自SQL 92 spec(在不同的地方):
如果未指定a,则Q行的排序依赖于实现