当前位置: 首页 > 科技观察

如何使用智能SQL查询来提升应用性能?

时间:2023-03-14 08:25:13 科技观察

【.com速译】为什么数据库会导致这么多性能问题?我们经常忘记每个请求都不是独立于其他请求的。如果一个请求很慢,它不太可能影响其他请求,不是吗?数据库是应用程序中运行的所有进程使用的共享资源。即使只有一个设计不当的访问也会拖累整个系统的性能。本文讨论了一些巧妙的SQL查询技术,这些技术彻底改变了我们系统的某些部分,提高了应用程序性能并最终改善了客户体验。如果您正在处理庞大的数据集、导入/导出流程、数据聚合算法和类似问题,这些解决方案可以帮助您大幅减少应用程序消耗的资源并节省资金。INSERTonDuplicateKeyUPDATEinsertonduplicatekeyupdate是鲜为人知的MySQL子句之一,但它在某些特定情况下保证了显着的性能提升,并实际上确保了客户体验。由于此子句,您可以指示MySQL运行UPDATE语句,以防INSERT语句由于表中可能存在重复键而失败。不妨举个真实的例子。CSV导入/导出假定从CSV文件导入用户列表的过程,其中每一行都需要有一个唯一的电子邮件地址。如果电子邮件地址已经存在,我们的脚本应该插入新用户并更新特定用户。此脚本的第一个版本可能是:PHP//CSVfilecontent$csv=[...];foreach($csvas$row){$user=User::firstWhere('email',$row['email']);if(!$user){$user=newUser()}$user->name=$row['name'];//"save"methodissmartenoughtoupdatearecordfitdoesnotexists,otherwisecreate.$user->save();}WetargetEach行验证数据库中是否已存在具有特定电子邮件的用户。如果用户存在,脚本更新其名称并保存;如果用户不存在,脚本会创建一个新的User实例,然后继续插入。在示例中,我们使用EloquentORM与数据库进行交互;“save()”方法足够智能,如果记录不存在则更新记录,否则创建记录。最后,我们运行一个选择以从数据库中获取用户,然后对INSERT或UPDATE记录执行另一个查询,因此对CSV文件中的每一行进行两次查询。这意味着对于具有500,000行的CSV,我们需要运行100万次查询(500,000次选择,500,000次插入或更新)。简化代码Eloquent和所有其他好的ORM都提供了某种捷径来做到这一点,因此我们可以使用updateOrCreate方法来减少行数并提高可读性://CSVfilecontent$csv=[...];foreach($csvas$row){User::updateOrCreate(//Identifyrecordbythiscolumns['email'=>$row['email']],//Otherfieldstofill['name'=>$row['email']]]);该方法实际上有一个非常清晰的名称并提供实用程序功能,但它还不够,因为它有同样的问题:对每个CSV行运行查询两次。太多的查询意味着太多的时间、CPU和内存使用。我们的目标是减少数据库语句的数量,从而优化性能和消耗的资源。如何使用“重复键”?此子句类似于“try/catch”语句,但适用于SQL。这是一个原始示例:INSERTINTOusers(email,name)VALUES('support@inspector.dev','Valerio')ONDUPLICATEKEYUPDATEusersSETname='Valerio';它的行为很简单:尝试插入一条包含指定信息的记录;如果没有报错,照常插入即可;如果查询抛出“重复键”错误,则继续提供的第二个查询。多亏了这个子句,我们可以将“if”语句从PHP移到数据库中,从而将对数据库本身的请求数量减少一半。让我们更进一步。我们还可以使用SQL语言进行批量操作,从而大大提高性能。我们可以添加多个INSERT并使用VALUES函数来引用正确的字段,例如循环中的变量。INSERTINTOusers(email,name)VALUES('support@inspector.dev','Valerio'),('support@inspector.dev','ValerioBarbera'),('frank@gmail.com','Frank'),('seb@gmail.com','Sebastian')ONDUPLICATEKEYUPDATEusersSETname=VALUES(名称);理论上,我们只需一次查询就可以导入整个CSV。在实践中,查询有长度限制,谨慎的做法是避免在一个操作中执行所有任务以避免内存不足错误。我们可以将CSV分成包含1000个项目的子组,并在其中运行包含1000个INSERT的查询://CSVfilecontent$csv=[...];$chunks=array_chunk($csv,1000);foreach($chunksas$chunk){foreach($chunkas$row){User::updateOrCreate(//Identifyrecordbythiscolumns['email'=>$row['email']],//Otherfieldstofill['name'=>$row['email']]]);}}1000只是一个例子,您可以根据您的服务器资源增加或减少这个数字。最重要的是,我们已将查询数量从500,000减少到500。EloquentUPSERT方法EloquentORM提供的upsert方法使您能够在后台实施此策略。用户::upsert([['email'=>'support@inspector.dev','name'=>'Valerio','age'=>25],['email'=>'support@inspector.dev','name'=>'ValerioBarbera','age'=>35]],['email'],['name','age']);该方法的第一个参数由要插入或更新的值组成,第二个参数列出了唯一标识关联表中记录的列。该方法的第三个也是最后一个参数是此类列的数组:如果数据库中已存在匹配记录,则应更新这些列。要使此方法起作用,upsert方法的第二个参数中的列需要具有“主要”或“唯一”索引。结论希望这一个或多个技巧将帮助您开发更可靠和可扩展的软件产品。我已经使用EloquentORM编写了代码示例,但您可以对所有主要ORM以相同的方式使用该策略。工具应该帮助我们实施有效的策略。战略思维是从长远角度看待我们产品的关键。原标题:HowtoAccelerateApplicationPerformanceWithSmartSQLQueries,作者:ValerioBarbera