Я начал с googling и нашел эту статью, которая рассказывает о таблицах мьютекса.
У меня есть таблица с ~ 14 миллионами записей. Если я хочу добавить больше данных в том же формате, есть ли способ гарантировать, что запись, которую я хочу вставить, уже не существует без использования пары запросов (т. Е. Один запрос для проверки и один для вставки – это набор результатов пусто)?
Ли unique
ограничение на поле гарантирует, что insert
не удастся, если она уже существует?
Похоже, что с просто ограничением, когда я выдаю вставку через php, скрипт скрипкает.
используйте INSERT IGNORE INTO table
см. http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
есть также INSERT … ON DUPLICATE KEY UPDATE
синтаксис, вы можете найти объяснения на dev.mysql.com
Сообщение от bogdan.org.ua в соответствии с веб-сайтом Google :
18 октября 2007 г.
Для начала: с момента последнего MySQL синтаксис, представленный в названии, невозможен. Но есть несколько очень простых способов добиться ожидаемого использования существующих функций.
Существует 3 возможных решения: использовать INSERT IGNORE, REPLACE или INSERT … ON DUPLICATE KEY UPDATE.
Представьте, что у нас есть таблица:
CREATE TABLE `transcripts` ( `ensembl_transcript_id` varchar(20) NOT NULL, `transcript_chrom_start` int(10) unsigned NOT NULL, `transcript_chrom_end` int(10) unsigned NOT NULL, PRIMARY KEY (`ensembl_transcript_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Теперь представьте, что у нас есть автоматический конвейер, импортирующий метаданные транскриптов из Ensembl, и что по разным причинам конвейер может быть разбит на любом этапе выполнения. Таким образом, нам нужно обеспечить две вещи: 1) повторные кавычки трубопровода не разрушат нашу базу данных, а 2) повторные казни не умрут из-за ошибок «дублировать первичный ключ».
Способ 1: использование REPLACE
Это очень просто:
REPLACE INTO `transcripts` SET `ensembl_transcript_id` = 'ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
Если запись существует, она будет перезаписана; если он еще не существует, он будет создан. Однако использование этого метода неэффективно для нашего случая: нам не нужно перезаписывать существующие записи, это просто, чтобы пропустить их.
Метод 2: использование INSERT IGNORE Также очень просто:
INSERT IGNORE INTO `transcripts` SET `ensembl_transcript_id` = 'ENSORGT00000000001′, `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
Здесь, если «ensembl_transcript_id» уже присутствует в базе данных, он будет пропущен (проигнорирован). (Точнее, вот цитата из справочного руководства MySQL: «Если вы используете ключевое слово IGNORE, ошибки, возникающие при выполнении инструкции INSERT, обрабатываются вместо этого. Например, без IGNORE строка, которая дублирует существующий индекс UNIQUE или PRIMARY KEY в таблице вызывает ошибку с дубликат-ключом, и оператор прерывается. ".) Если запись еще не существует, она будет создана.
Этот второй метод имеет несколько потенциальных недостатков, включая неабортировку запроса в случае возникновения какой-либо другой проблемы (см. Руководство). Таким образом, он должен использоваться, если ранее был протестирован без ключевого слова IGNORE.
Существует еще один вариант: использовать INSERT … ON DUPLICATE KEY UPDATE синтаксис, а в части UPDATE ничего не делают, делая какую-то бессмысленную (пустую) операцию, например вычисление 0 + 0 (Geoffray предлагает сделать id = id для оптимизации MySQL чтобы игнорировать эту операцию). Преимущество этого метода заключается в том, что он игнорирует только повторяющиеся ключевые события и все еще прерывает другие ошибки.
Как последнее замечание: этот пост был вдохновлен Xaprb. Я также советую проконсультироваться с его другим сообщением о написании гибких SQL-запросов.
INSERT INTO `table` (value1, value2) SELECT 'stuff for value1', 'stuff for value2' FROM `table` WHERE NOT EXISTS (SELECT * FROM `table` WHERE value1='stuff for value1' AND value2='stuff for value2') LIMIT 1
В качестве альтернативы внешний SELECT
может ссылаться на DUAL
, чтобы обрабатывать случай, когда таблица изначально пуста:
INSERT INTO `table` (value1, value2) SELECT 'stuff for value1', 'stuff for value2' FROM DUAL WHERE NOT EXISTS (SELECT * FROM `table` WHERE value1='stuff for value1' AND value2='stuff for value2') LIMIT 1
при дублировании ключевого обновления или вставке ignore могут быть жизнеспособными решениями с MySQL.
Пример обновления дублирующего ключевого обновления на основе mysql.com
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=c+1; UPDATE table SET c=c+1 WHERE a=1;
Пример игнорирования вставки на основе mysql.com
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] {VALUES | VALUE} ({expr | DEFAULT},...),(...),... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
Или:
INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name SET col_name={expr | DEFAULT}, ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
Или:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE] [INTO] tbl_name [(col_name,...)] SELECT ... [ ON DUPLICATE KEY UPDATE col_name=expr [, col_name=expr] ... ]
Любое простое ограничение должно выполнять эту работу, если исключение является приемлемым. Примеры :
Извините, это кажется обманчиво простым. Я знаю, что это плохо противостоит той ссылке, которую вы разделяете с нами. ;-(
Но я никогда не даю этого ответа, потому что он, похоже, наполнит ваши потребности. (Если нет, это может спровоцировать ваше обновление ваших требований, что также будет «хорошей вещью» (TM).
Отредактировано : если вставка будет разбивать единственное ограничение базы данных, исключение – это выброс на уровне базы данных, передаваемый драйвером. Это, безусловно, остановит ваш скрипт с ошибкой. Должно быть возможно в PHP, чтобы это дело …
REPLACE INTO `transcripts` SET `ensembl_transcript_id` = 'ENSORGT00000000001', `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
Если запись существует, она будет перезаписана; если он еще не существует, он будет создан.
Вот PHP-функция, которая будет вставлять строку только в том случае, если все указанные значения столбцов еще не существуют в таблице.
Если один из столбцов отличается, строка будет добавлена.
Если таблица пуста, строка будет добавлена.
Если строка существует, где все указанные столбцы имеют указанные значения, строка не будет добавлена.
function insert_unique($table, $vars) { if (count($vars)) { $table = mysql_real_escape_string($table); $vars = array_map('mysql_real_escape_string', $vars); $req = "INSERT INTO `$table` (`". join('`, `', array_keys($vars)) ."`) "; $req .= "SELECT '". join("', '", $vars) ."' FROM DUAL "; $req .= "WHERE NOT EXISTS (SELECT 1 FROM `$table` WHERE "; foreach ($vars AS $col => $val) $req .= "`$col`='$val' AND "; $req = substr($req, 0, -5) . ") LIMIT 1"; $res = mysql_query($req) OR die(); return mysql_insert_id(); } return False; }
Пример использования:
<?php insert_unique('mytable', array( 'mycolumn1' => 'myvalue1', 'mycolumn2' => 'myvalue2', 'mycolumn3' => 'myvalue3' ) ); ?>
Попробуйте следующее:
IF (SELECT COUNT(*) FROM beta WHERE name = 'John' > 0) UPDATE alfa SET c1=(SELECT id FROM beta WHERE name = 'John') ELSE BEGIN INSERT INTO beta (name) VALUES ('John') INSERT INTO alfa (c1) VALUES (LAST_INSERT_ID()) END
Replace
может сработать для вас.
Пытаться:
// Check if exist cod = 56789 include "database.php"; $querycheck = mysql_query ("SELECT * FROM `YOURTABLE` WHERE `xxx` = '56789';"); $countrows = mysql_num_rows($querycheck); if($countrows == '1') { // Exist } else { // .... Not exist }
Или вы можете сделать:
// Check if exist cod = 56789 include "database.php"; $querycheck = mysql_query ("SELECT * FROM `YOURTABLE` WHERE `xxx` = '56789';"); $countrows = mysql_num_rows($querycheck); while($result = mysql_fetch_array($querycheck)) { $xxx = $result['xxx']; if($xxx == '56789') { // Exist } else { // Not exist } }
Этот метод является быстрым и легким. Для улучшения скорости запроса в вашей большой таблице столбцы INDEX «xxx» (в моем примере).
Есть несколько ответов, которые описывают, как решить эту проблему, если у вас есть индекс UNIQUE
которым вы можете проверить с помощью ON DUPLICATE KEY
или INSERT IGNORE
. Это не всегда так, и поскольку UNIQUE
имеет ограничение длины (1000 байт), вы не сможете его изменить. Например, мне пришлось работать с метаданными в WordPress ( wp_postmeta
).
Я, наконец, решил это с двумя запросами:
UPDATE wp_postmeta SET meta_value = ? WHERE meta_key = ? AND post_id = ?; INSERT INTO wp_postmeta (post_id, meta_key, meta_value) SELECT DISTINCT ?, ?, ? FROM wp_postmeta WHERE NOT EXISTS(SELECT * FROM wp_postmeta WHERE meta_key = ? AND post_id = ?);
Запрос 1 – это регулярный запрос UPDATE
без эффекта, если такого набора данных нет. Запрос 2 является INSERT
который зависит от NOT EXISTS
, т.е. INSERT
выполняется только тогда, когда набор данных не существует.
вы можете либо запустить быстрый выбор, чтобы найти, существует ли он, а затем ничего не вставлять, они будут двумя инструкциями
или просто
INSERT IGNORE INTO стол