我目前有一个SQL执行脚本,用于更新重复键上的行,如下所示。
$stmt = $dbCon->prepare("INSERT INTO videos_rating (videos_rating_video_fk, "
. " videos_rating_user_fk, "
. " videos_rating_rating) "
. " VALUES (:video_id, "
. " :user_id, "
. " :video_rating) "
. " ON DUPLICATE KEY UPDATE videos_rating_rating = :video_rating");
该脚本运行正常但有没有办法阻止自动增量列不同步?
让我们假设我们从一个空表开始,然后我对一个视频进行评级,然后创建一个将获得id为1的行,然后用户通过将相同的视频评级为更低或更高的评级再次执行SQL将更新,因为它现在是一个重复的键,确定没问题。
问题在于此。
下次其他用户对新视频进行评分时,该行现在将从ID 3开始,而不是2?
该表将如下所示
id | videos_rating_user_fk | videos_rating_rating
1 | 1 | 4
3 | 2 | 5
我甚至找不到类似的问题,即使我发现没有其他人不会对此感到困扰,如果是这样,请将我推荐给那篇文章。
我知道ids不应该看起来很好'但是ids从30 - 51 - 82 - 85 - 89等跳出来并且在达到最大UNSIGNED大的int数时会不会出现问题是非常烦人的?我不是说我会那么高,但仍然。
答案 0 :(得分:2)
我假设您使用的是默认的 InnoDB 引擎。在那种情况下,"问题"是引擎将"保留"之前的id知道它是否重复。一旦id被"保留"它无法释放,因为另一个线程(另一个用户)可能会在"同一个"时间。还有其他方法可以在AUTO_INCREMENT列中获取间隙而不删除任何行。一种是回滚交易。
您可以尝试重置"每次插入
后的下一个AUTO_INCREMENT值alter table videos_rating auto_increment = 1;
但我无法说明在正在运行的实时环境中执行此语句时可能遇到的问题。我不会发现那个。
请注意,这通常不是问题,因为运行IODKU状态的表(通常)不需要AUTO_INCREMENT列。正如Cid在他的回答中写道,你可以放弃id
列并将你的唯一密钥定义为主键。
答案 1 :(得分:1)
我们假设您的表是以这种方式构建的:
videos_rating_video_fk | videos_rating_user_fk | videos_rating_rating
-----------------------+-----------------------+----------------------
第一个键videos_rating_video_fk
应该是外键而不是具有自动增量的主键。
如果用户1和2投票选择了id
1的视频,那么 的表格应如下所示:
videos_rating_video_fk | videos_rating_user_fk | videos_rating_rating
-----------------------+-----------------------+----------------------
1 | 1 | 4
1 | 2 | 5
对于那种表格,主键应该是两个外键的组合,并且是唯一的。用户只能对视频投票一次(唯一投票=唯一密钥)。视频可以由多个用户投票,用户可以投票选择多个视频。
我建议你看一下Merise方法,用于构建具有完整性约束和创建主键的表。
答案 2 :(得分:1)
与ids的“燃烧”一起生活。 AUTO_INCREMENT
保证不允许重复值,不不提供任何其他保证。
有大约4种其他方式可以将 “烧掉”:REPLACE
,多主/加莱拉,IGNORE
,DELETE
,以及可能更多。
IODKU在发现声明变成UPDATE
并且不需要id之前迅速抓住了id。否则可能会对性能造成重大影响。
答案 3 :(得分:0)
为了确认,Paul Spiegel的回答帮助我解决了这个问题。我有一个'Upsert'SQL查询,该查询使用ON DUPLICATE KEY UPDATE
确定是创建新行还是更新现有行。在行频繁更新的地方,所分配的ID的跳转会很大。
“问题”是引擎在知道ID是否重复之前会“保留”该ID。
我通过将SQL代码分成单独的INSERT和UPDATE语句解决了该问题。我再也看不到问题了。