单条数据和少量数据的更新插入,操作简单,不需要过多考虑SQL语句怎么写。通常是根据条件判断数据是否已经存在于表中,有更新,没有插入。如果有N条数据,则最多执行2N条SQL语句。当N值不大的时候,可以用这种简单的方法进行update和insert。但是,当N数据量不可预测或者很大时,肯定不能这样做。执行该操作时,可能会耗尽MySQL连接数,导致系统资源耗尽,影响其他操作。以MySQL为例进行批量插入。网上有很多SQL例子:下面是两个批量插入SQLinsertintotable(`column1`,`column2`,`column3`)values(1,2,3),(2,3,4),(5,6,7)insertintotable(`column1`,`column2`,`column3`)select1,2,3unionallselect2,3,4unionallselect4,5,6下面是在MySQL5.79,第二种方式插入3次2527条数据需要时间,供参考[2018-12-0510:58:59]452ms影响1000行[2018-12-0511:04:54]1000rowsinaffectedin389ms[2018-12-0511:06:12]527rowsaffectedin163msbatchupdate批量更新有几种方式,一:replaceintotable(`column1`,`column2`,`column3`)values(1,2,3),(2,3,4),(5,6,7)相当于将数据库中的数据与要插入的数据进行交集,删除交集的数据并resettinginsert.表中的自增id会发生变化,当没有其他与数据相关的唯一键或表中有其他需要的数据时不适用ds要累积或与其他表相关联。本文有详细介绍2:INSERTINTOt1(a,b,c)VALUES(1,2,3)ONDUPLICATEKEYUPDATEc=c+1;UPDATEt1SETc=c+1WHEREa=1;这种更新需要用一个唯一的key来限制。同时更新字段的取值限制比较大,需要更新的字段的值无法自定义。只能按照一定的逻辑进行更新,可能会用在类似于签到计数的场景。本文有详细介绍三:updatetablesetcolumn1=casewhencolumn2=1then2else3end,column3=casewhencolumn4=1then2else3endwhereidin(1,2,3,4)useWithMySQL的casewhen函数,可以根据不同的条件对不同的字段更新不同的值,可以为语句定义不同的条件。接下来使用PHP实现如下拼装SQL语句的过程://批量拼装并条件更新SQL语句protectedfunctionhandleUpdate($data,$key){if(empty($data)||!is_array($data)){返回错误;}$keys_array=array_keys(current($data));//要更新的字段$update_column=[$keys_array[5],$keys_array[6],$keys_array[8],$keys_array[9],$keys_array[16],$keys_array[14]];//更新条件$vehicle_id=$keys_array[2];$body_color=$keys_array[3];$interior_color=$keys_array[4];$city_id=$keys_array[11];$province_id=$keys_array[10];$q="更新ce集";foreach($update_columnas$update_colum){$q.=''.$更新列。'=案例';foreach($dataas$value){$value[$update_colum]=!isset($value[$update_colum])||空($值[$update_colum])?0:$值[$update_colum];$q.='什么时候'。$vehicle_id。'='。$值[$vehicle_id]。'和'。$身体颜色。'="'.$value[$body_color].'"'.'和'。$interior_color。'="'.$value[$interior_color].'"'.'和'。$城市编号。'='。$值[$city_id]。'和'。$province_id。'然后'。$值[$update_colum];}$q.=“其他”。$更新列。“结尾,”;}$q=rtrim($q,",");}表结构如下--自动生成定义createtablecd(idintauto_incrementprimarykey,brand_idintdefault'0'notnullcomment'vehiclebrandid',model_idintdefault'0'notnullcomment'vehiclemodelid',vehicle_idintdefault'0'notnullcomment'Vehiclemodelid',body_colorvarchar(50)default''notnullcomment'Bodyexteriorcolor',interior_colorvarchar(50)default''notnullcomment'vehicleinteriorcolor',guide_pricedecimal(8,2)default'0.00'notnullcomment'guideprice',province_idintdefault'0'notnullcomment'provinceid',provincevarchar(50)default''notnullcomment'省名',city_idintdefault'0'notnullcomment'地级市id',cityvarchar(50)default''notnullcomment'地级市名',report_pricedecimal(8,2)default'0.00'notnullcomment'Groupprice',average_pricedecimal(8,2)default'0.00'notnullcomment'averageprice',coefficientfloat(5,2)default'0.00'notnullcomment'coefficient',price_increasedecimal(8,2)default'0.00'notnullcomment'priceincrease',operatorintdefault'0'notnullcomment'operatorid',created_atintdefault'0'notnullcomment'creationtime',updated_atintdefault'0'notnullcomment'updatetime',constraintunique__indexunique(vehicle_id,body_color,interior_color,city_id,province_id))评论'';判断需要插入和更新的数据1:保证数据唯一,只需要保证一个值身份证的一个字段简单处理可以取出数组中的值,然后查询数据库即可判断是否存在。$where_in=array_column($array,'column');//所有数据的查找条件;$res=mysql_execute('selectcolumnfromtablewherecolumnin('.$where_in.')');//MySQL执行$res_in=array_column($res,'column');//查找数据库中已有的数据根据搜索条件;$update_arr=array_diff($where_in,$res_in);//获取数据库中没有的数据$update_info=array_filter($array,function($item)use($update_arr){returnin_array($item['column'],$update_arr)?true:false;});//获取更新数据$insert_info=array_filter($array,function($item)use($res_in){returnin_array($item['column'],$update_arr)?true:false;});//获取并插入数据2:多条件过滤我的解决方法和上面类似,只是不能使用wherecolumnin这样的条件从数据库中过滤,主要是因为索引的问题,当表数据很大的时候就不适合了。于是用Redis的一套来解决。将查询条件记录在集合中,只需要遍历数组,判断当前数据中的查询条件是否在Rediskey中。主要是使用第三方存储条件,当然也可以使用MySQL来保证查询效率。附加优化1:为避免加载的数组过大占用内存,可以使用yield分片,每次输出量化数据,然后遍历执行。二:可以使用队列来批量执行任务。使用Redis或者RabbitMQ等。三:好像可以试试swoole的协程,好像很强大。以上就是我在做项目的过程中遇到的问题和自己的想法。如果您有不同的想法或觉得不妥,欢迎提出。
