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) のデータベースサーバ再起動したくないしなぁ。というあたりでやる気が起きない。