php - INSERT ON DUPLICATE KEY UPDATE 导致较大的增量差距 - InnoDB MySQL

标签 php mysql sql

我正在尝试将关键字插入到 keyword 表中,并通过 articleKeywordIndex 表将它们映射到 articles,但卡住了车辙,不能出去。这是我的设置:

articles
-------------
articleID    INT AUTO PRI

articleKeywordIndex
-------------
articleID    INT UNIQUE
keywordID    INT UNIQUE

keywords
-------------
keywordID    INT PRI
keyword      VARCHAR UNIQUE

使用 INSERT INTO keywords (a) VALUES (:a) ON DUPLICATE KEY UPDATE a = a 但我注意到自动增量被奇怪地更新了这让我感到困惑,因为我认为这是避免这种情况发生的方法。无论如何,我还需要获取 keywordID 是否存在,以放入混频器表中,所以我转而使用 try/catch 解决方案,如果 INSERT 由于唯一条目而失败, catch 将选择该 keywordID 以在另一个表中使用。

现在发生的事情是,如果关键字不存在,并且该表中已经有 4 个关键字 (1,2,3,4),则关键字表中的 keywordID 列递增 4,使其变为 8当它被插入时。如果这种情况持续发生并且我有很多关键字,则 keywordID 列的 ID 将是 huuuuge!如果关键字确实存在,则不会发生任何变化并且可以完美运行。我想这与循环循环 4 次有关,但我看不出问题所在。

代码如下:

$tagsArray = explode(',', strtolower($tags));
for ($x = 0; $x < count($tagsArray); $x++) {

    $keyword = trim($tagsArray[$x]);

    try {
        $SQL = "INSERT INTO keywords (keyword) VALUES (:keyword);";
        $STH = $DBH -> prepare($SQL);
        $STH -> bindParam(':keyword', $keyword);
        $STH -> execute();
        $keywordID = $DBH -> lastInsertId();
    } catch (Exception $e) {
        $SQL = "SELECT keywordID FROM keywords WHERE keyword = :keyword;";
        $STH = $DBH -> prepare($SQL);
        $STH -> bindParam(':keyword', $keyword);
        $STH -> execute();
        $keywordID = $STH -> fetchColumn();
    }

    $SQL = "INSERT INTO articleKeywordIndex (articleID, keywordID) VALUES (:saveToID, :keywordID)
        ON DUPLICATE KEY UPDATE articleID = articleID, keywordID = keywordID;";
    $STH = $DBH -> prepare($SQL);
    $STH -> bindParam(':saveToID', $saveToID);
    $STH -> bindParam(':keywordID', $keywordID);
    $STH -> execute();

}

我想这不是什么大问题,因为我只会使用大约 3000-5000 个关键字,但它仍然很烦人,我想知道哪里出了问题。

解决方案

事实证明,在使用 INSERT ON DUPLICATE KEY UPDATE 时,使用 InnoDB 引擎会导致奇怪的增量更改。这实际上在几年前被报告为一个错误,并分发了一个补丁,但后来证明这是一个有意设计的功能,my.cnf 中的一个设置禁用了它。很奇怪的故事,花了一段时间才了解它。无论如何,在 my.cnf 中,我改变了这个:

innodb_autoinc_lock_mode=0

一切都恢复正常了,我的脚本像我第一次写它时所想的那样工作,在其他五次尝试之前!!我正在使用 InnoDB 进行事务,所以我不准备仅仅因为这个而切换到 MyISAM。

最佳答案

你的代码看起来没问题?我可能会尝试以下操作,看看是否有任何效果。

  • 首先,使用 SELECT @@auto_increment_increment; 检查 auto_increment_increment。也许由于某种原因它被设置为 4?

  • 如果您使用 mySQL 手动添加记录怎么办?还会涨4吗?如果是,那么可能与您的代码无关。

  • 你说可能和loop循环4次有关。您是否尝试过使用化妆阵列来制作带有 say...6 元素的循环?它会上升 6 吗?

  • 我还会检查并确保没有任何隐藏的程序或触发器在幕后执行操作。

EDIT1:将准备移出循环。我认为无论有没有 on update 你似乎仍然有奇怪的增量问题,不妨再次使用 ...on update

$tagsArray = explode(',', strtolower($tags));
$SQL = "INSERT INTO keywords (keywordID, keyword) VALUES (NULL, :keyword) 
            ON DUPLICATE KEY UPDATE keywordID=LAST_INSERT_ID(keywordID), keyword = keyword;
        INSERT INTO articleKeywordIndex (articleID, keywordID) VALUES (:saveToID, LAST_INSERT_ID())
            ON DUPLICATE KEY UPDATE articleID = articleID, keywordID = keywordID;";
$STH = $DBH -> prepare($SQL);
$STH -> bindParam(':saveToID', $saveToID);   //<--I actually haven't tried this, if it doesn't work move it back into loop.

for ($x = 0; $x < count($tagsArray); $x++) {
        $STH -> bindParam(':keyword', trim($tagsArray[$x]));
        $STH -> execute();
}

关于php - INSERT ON DUPLICATE KEY UPDATE 导致较大的增量差距 - InnoDB MySQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25172543/

相关文章:

sql - 将输出写入 postgreSQL 中的文件?

javascript - 如何将文本字段中的填充值保存到 Ionic 6/Capacitor 中的 SQLite 数据库?

php - 如何在数据库中相应地保存 gmail 电子邮件

php - 发送一个非阻塞的 HTTP POST 请求

php - MySql 和 PDO : How to send a null param with bindParam()

PHP 错误未定义属性:CodeIgniter 2 中的 stdClass::$barang

sql - sqlserver中如何修改主键值?

php - 需要路由到不同的 php 文件并使用 .htaccess 调用单独的函数

php - 搜索引擎只能单返回?

mysql - Node/Express/Sequelize : Datatype VIRTUAL gives SQL syntax error in db:migration