MySQL でユニークキーからプライマリIDへ変換 (存在しない場合の追加しつつ) を1クエリで書く方法

たとえば、以下のような url テーブルから

CREATE TABLE url (
  id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
  url VARCHAR(255) NOT NULL,
  UNIQUE KEY url (url)
);

primary id を (存在しない場合は URL を追加しつつ) 検索する場合、

INSERT INTO url (url) VALUES ('http://example.com') ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);

とやって、あとは last_insert_id の値 (perl の場合は $dbh->{mysql_insertid}) を参照すればいい *1。テーブルルックアップも1回だしクエリの送受信も1回なので速い。ただ、MySQL 5.1 以降かつ InnoDB の場合は、

innodb_autoinc_lock_mode=traditional

にセットしておかないと url.id が飛び飛びの値になる。てか InnoDB の中の人が ON DUPLICATE KEY UPDATE 〜の動作をよくしらねとか言ってるし、上のような特殊ケースまで頭がまわってないんだと思う。

参考: MySQL Bugs: #28781: InnoDB increments auto-increment value incorrectly with ON DUPLICATE KEY UPDATE

innodb_autoinc_lock_mode=traditional は並走度が下がるし、直したいなとは思うんだけど、パストラック (pathtraq) のデータベースサーバ再起動したくないしなぁ。というあたりでやる気が起きない。