war*_*ren 781 php mysql sql performance primary-key
我开始使用谷歌搜索,发现这篇文章讨论了互斥表.
我有一张约有1400万条记录的表格.如果我想以相同的格式添加更多数据,有没有办法确保我想要插入的记录不存在而不使用一对查询(即,一个查询要检查,一个要插入是结果集是空)?
unique
对某个字段的约束是否保证insert
如果它已经存在则会失败?
似乎只有一个约束,当我通过php发出插入时,脚本呱呱叫.
kni*_*ttl 756
使用 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 :
2007年10月18日
首先:从最新的MySQL开始,标题中提供的语法是不可能的.但是有几种非常简单的方法可以实现使用现有功能所期望的功能.
有3种可能的解决方案:使用INSERT IGNORE,REPLACE或INSERT ... ON DUPLICATE KEY UPDATE.
想象一下,我们有一张桌子:
Run Code Online (Sandbox Code Playgroud)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
这很简单:
Run Code Online (Sandbox Code Playgroud)REPLACE INTO `transcripts` SET `ensembl_transcript_id` = 'ENSORGT00000000001', `transcript_chrom_start` = 12345, `transcript_chrom_end` = 12678;
如果记录存在,它将被覆盖; 如果它还不存在,它将被创建.但是,对于我们的情况,使用此方法效率不高:我们不需要覆盖现有记录,只需跳过它们就可以了.
方法2:使用INSERT IGNORE也非常简单:
Run Code Online (Sandbox Code Playgroud)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建议为MySQL优化做id = id赋值引擎忽略此操作).此方法的优点是它只忽略重复的键事件,并仍然中止其他错误.
最后通知:这篇文章的灵感来自Xaprb.我还建议查阅他关于编写灵活SQL查询的其他帖子.
小智 186
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)
Run Code Online (Sandbox Code Playgroud)
或者,外部WHERE NOT EXISTS
语句可以引用LIMIT 1
以便处理表最初为空的情况:
SELECT * FROM `table`
WHERE `value1`='stuff for value1' AND `value2`='stuff for value2' LIMIT 1
Run Code Online (Sandbox Code Playgroud)
Zed*_*Zed 55
基于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;
Run Code Online (Sandbox Code Playgroud)
基于mysql.com 的insert ignore示例
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] ... ]
Run Code Online (Sandbox Code Playgroud)
要么:
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] ... ]
Run Code Online (Sandbox Code Playgroud)
要么:
INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
[INTO] tbl_name [(col_name,...)]
SELECT ...
[ ON DUPLICATE KEY UPDATE
col_name=expr
[, col_name=expr] ... ]
Run Code Online (Sandbox Code Playgroud)
KLE*_*KLE 24
如果可以接受异常,任何简单约束都应该完成.例子 :
对不起,这看起来很简单.我知道您与我们分享的链接看起来很糟糕.;-(
但我永远不会给出这个答案,因为它似乎满足了你的需要.(如果没有,它可能会触发您更新您的要求,这也是"好事"(TM)).
编辑:如果插入会破坏数据库唯一约束,则会在数据库级别抛出异常,由驱动程序中继.它肯定会因为失败而停止你的脚本.PHP必须能够解决这个问题......
小智 19
这是一个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;
}
Run Code Online (Sandbox Code Playgroud)用法示例:
<?php
insert_unique('mytable', array(
'mycolumn1' => 'myvalue1',
'mycolumn2' => 'myvalue2',
'mycolumn3' => 'myvalue3'
)
);
?>
Run Code Online (Sandbox Code Playgroud)
小智 18
REPLACE INTO `transcripts`
SET `ensembl_transcript_id` = 'ENSORGT00000000001',
`transcript_chrom_start` = 12345,
`transcript_chrom_end` = 12678;
Run Code Online (Sandbox Code Playgroud)
如果记录存在,它将被覆盖; 如果它还不存在,它将被创建.
小智 17
请尝试以下方法:
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
Run Code Online (Sandbox Code Playgroud)
有几个答案可以解决如何解决这个问题,如果你有一个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 = ?);
Run Code Online (Sandbox Code Playgroud)
查询1是常规UPDATE
查询,当有问题的数据集不存在时,该查询无效.查询2 INSERT
取决于a NOT EXISTS
,即INSERT
仅在数据集不存在时执行.
值得注意的是,无论语句是否成功,INSERT IGNORE 仍然会增加主键,就像普通的 INSERT 一样。
这会导致主键出现间隙,从而可能使程序员精神不稳定。或者,如果您的应用程序设计不佳并且依赖于完美的增量主键,那么它可能会变得令人头疼。
查看innodb_autoinc_lock_mode = 0
(服务器设置,并且会带来轻微的性能影响),或者首先使用 SELECT 以确保您的查询不会失败(这也会带来性能影响和额外的代码)。
归档时间: |
|
查看次数: |
655698 次 |
最近记录: |