【发布时间】:2023-03-06 13:28:01
【问题描述】:
目前我有一个大约 300 万行 (listings) 的 MySQL 表。这些列表由 python 脚本 (Scrapy) 使用 pymsql 更新 24/7(大约 30 个列表/秒) - 因此查询的性能是相关的!
如果listing 不存在(即UNIQUE url),将插入一条新记录(大约每百分之一列表)。 id 设置为 auto_increment,我使用的是 INSERT INTO listings ... ON DUPLICATE KEY UPDATE last_seen_at = CURRENT_TIMESTAMP。 last_seen_at 上的更新对于检查该项目是否仍然在线是必要的,因为我正在抓取包含多个列表的搜索结果页面,而不是每次都检查每个单独的 URL。
+--------------+-------------------+-----+----------------+
| Field | Type | Key | Extra |
+--------------+-------------------+-----+----------------+
| id | int(11) unsigned | PRI | auto_increment |
| url | varchar(255) | UNI | |
| ... | ... | | |
| last_seen_at | timestamp | | |
| ... | ... | | |
+--------------+-------------------+-----+----------------+
问题:
一开始,一切都很顺利。然后我注意到 auto_incremented id 列中的差距越来越大,并发现这是由于INSERT INTO ... 语句:MySQL 尝试先进行插入。这是id 自动递增的时候。一旦增加,它就会保持不变。然后检测到重复并进行更新。
现在我的问题是:从长远的角度来看,关于性能的最佳解决方案是什么?
选项 A: 将 id 列设置为无符号 INT 或 BIGINT 并忽略间隙。这里的问题是我害怕在几年更新后达到最大值。经过两天的更新,对于大约 3,000,000 个列表,我的 auto_increment 值已经达到了大约 12,000,000...
选项 B: 切换到 INSERT IGNORE ... 语句,检查受影响的行并在必要时检查 UPDATE ...。
选项 C: SELECT ... 现有列表,检查是否存在于 python 和 INSERT ... 或 UPDATE ... 取决于。
还有其他明智的选择吗?
附加信息:我需要一个id 来获取与存储在其他表中的listing 相关的信息(例如listings_images、listings_prices 等)。恕我直言,使用 URL(这是唯一的)不是外键的最佳选择。
+------------+-------------------+
| Field | Type |
+------------+-------------------+
| listing_id | int(11) unsigned |
| price | int(9) |
| created_at | timestamp |
+------------+-------------------+
【问题讨论】:
-
第四个选项可能是删除 auto_increment id 列。
-
@P.Salmon 是的,这就是我在回答中建议的,不需要 ID 列,只需将 URL 设为 PRIMARY KEY 并在其上添加唯一索引
-
@P.Salmon 我添加了信息,有更多的表存储有关列表的信息,因此我需要一个
id- 使用长字符串 URL 不是最好的选择这个案例。纠正我,如果我错了。
标签: mysql insert scrapy sql-update insert-update