为什么在导入CSV之后,数据库表中的数据会按字母顺序存储?
为什么我的CSV文件导入数据库时,第一列 product_key 的字母序被排序?不是按行逐行,从CSV的第一行到最后一行导入吗?
我的CSV并非按 product_key 排序,但导入后,行在 my_table 中按字母顺序排列,如在PHPMyAdmin中所见。表为 InnoDB。
我在INSERT语句中没有使用ASC或 DESC
我想弄清楚这个原因,因为在一个页面上,我在CSV文件上传表单下方显示表中的数据,我希望数据的显示顺序与上传的文件保持一致。
编辑3/26/26:
SHOW CREATE TABLE显示如下:
vw_star_ratings CREATE TABLE `vw_star_ratings` (
`product_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL,
`ID_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL,
`value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_520_ci NOT NULL,
UNIQUE KEY `key_index` (`product_key`,`ID_key`,`value`),
KEY `product_key` (`product_key`),
KEY `ID_key` (`ID_key`),
KEY `value` (`value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
有什么想法吗?
$file = fopen($fileTmpPath, "r");
// Start transaction
$pdo->beginTransaction();
$stmt = $pdo->prepare("
INSERT INTO my_table (product_key, ID_key, value)
VALUES (?, ?, ?)
");
// Skip header
fgetcsv($file);
while (($row = fgetcsv($file, 1000, ",")) !== FALSE) {
if (count($row) < 3) continue;
$stmt->execute([$row[0], $row[1], $row[2]]);
}
fclose($file);
$pdo->commit();
解决方案
上述评论的要点:
- 你的表有这个索引:
UNIQUE KEY key_index (product_key,ID_key,value)。由于这三列都是NOT NULL,并且表使用InnoDB存储引擎,这意味着这三列构成了表的聚簇索引。有关此的文档,请参阅 https://dev.mysql.com/doc/refman/en/innodb-index-types.html。 - InnoDB会根据这三列对聚簇索引中的行进行排序存储,product_key位于第一位。
- 当你对InnoDB表进行查询且未指定
ORDER BY子句时,数据库会按照优化器选择的任意索引的顺序读取行,若未使用其他索引,则按聚簇索引的顺序读取。这就是在你导入数据后,默认排序会按product_key的原因。
至少这是当前InnoDB实现中的行为,但没有文档化,你不应该依赖它。 * 强制按你插入的顺序存储行的一种解决方法是添加一个自增列:
ALTER TABLE vw_star_ratings ADD COLUMN id INT AUTO_INCREMENT PRIMARY KEY;
这会添加一个列和一个主键。然后按之前的方式导入你的CSV数据。由于你的 INSERT 指定了列,省略新列后,这使得自增 id 能够自动生成值,按你插入数据的顺序。
* 当你想要特定排序时,最佳做法是在查询中显式使用 ORDER BY。任何出现的默认排序都不可靠,可能会改变,例如InnoDB选择了不同的索引。
SELECT ... FROM vw_star_ratings ORDER BY id;
如果优化器无论如何都会按这个顺序读取行,那么 ORDER BY 就是一个无操作,对性能没有影响。至少你的代码对阅读它的其他人来说更能体现意图。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。