Я начал с googling и нашел эту статью , которая рассказывает о таблицах мьютекса.
У меня есть таблица с ~ 14 миллионами записей. Если я хочу добавить больше данных в том же формате, есть ли способ гарантировать, что запись, которую я хочу вставить, уже не существует без использования пары запросов (т.е. Один запрос для проверки и один для вставки - это набор результатов пусто)?
Ограничение unique
в поле гарантирует, что insert
завершится с ошибкой, если он уже существует?
Похоже, что с просто ограничением, когда я выдаю вставку через php, script кричит.
использовать 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 уже присутствует в базы данных, он будет пропущен (проигнорирован). (Если быть более точным, heres цитата из справочного руководства 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
при дублировании ключевого обновления или insert 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).
Отредактировано. Если вставка нарушит уникальное ограничение базы данных, исключение - это выброс на уровне базы данных, передаваемый драйвером. Это, безусловно, остановит ваш script с ошибкой. В PHP должно быть возможно указать этот случай...
Вот 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'
)
);
?>
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Если запись существует, она будет перезаписана; если он еще не существует, он будет создан.
REPLACE
может удалить строку, а затем вставить вместо обновления. Побочным эффектом является то, что ограничения могут удалять другие объекты и запускать триггеры удаления.
Попробуйте следующее:
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
может работать для вас.
Try:
// 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
, который зависит от a NOT EXISTS
, т.е. INSERT
выполняется только тогда, когда набор данных не существует.
вы можете либо запустить быстрый выбор, чтобы найти, существует ли он, а затем ничего не вставлять, они будут двумя инструкциями
или просто перейдите к
INSERT IGNORE INTO таблица