在我来工作的公司,他们运行一个 PHP/MySQL 关系数据库。我一直认为,如果我需要从不同的表中提取不同的信息,我可以做一个简单的连接来提取数据,例如......
SELECT table_1.id, table_2.id FROM table_1 LEFT JOIN table_2 ON table_1.sub_id = table_2.id
当我到达我目前工作的地方时,他们就是这样做的。
<?php $query = mysql_query("SELECT sub_id FROM table_1");
while($rs = mysql_fetch_assoc($query)) {
$query_2 = mysql_fetch_assoc(mysql_query("SELECT * FROM table_2 WHERE id = '{$rs['sub_id']}'"));
//blah blah blah more queries
?>
当我问为什么采用第二种方式时,他们说它实际上比连接运行得更快。他们管理一个数据库,该数据库在不同的表上有数百万条记录,并且一些表有点宽(按行)。他们说他们希望在执行不当的查询可能锁定一个表(或多个表)的情况下避免连接。另一件要记住的事情是,有一个大型报告生成器附加到该数据库,客户可以使用它来构建自己的报告,如果他们疯狂地构建一个大报告,可能会造成一些破坏。
我很困惑,所以我想我应该把它扔给一般的编程公众。这可能是一个见仁见智的问题,但是做 while 语句(一个更大的查询来拉很多行,如果你愿意的话,后面跟着很多小的子查询)或做一个连接(拉一次更大的查询以获得所需的所有数据)。只要索引做得好,有关系吗?另一件需要考虑的事情是当前的数据库是 InnoDB 格式。
谢谢!
2014 年 8 月 28 日更新
所以我想我应该对这个进行更新,以及更长期有效的方法。经过这次讨论,我决定在工作中重建报告生成器。我没有确定的结果数字,但我想我会分享结果是什么。
我认为有点矫枉过正,因为我将整个报告(就返回的数据而言,它非常动态)变成了一个巨大的连接盛宴。大多数联接(如果不是全部)都将值联接到主键,因此它们都运行得非常非常快。如果报告有 30 列数据要提取,它提取了 2000 条记录,则每个字段都运行一个查询来获取数据(因为那部分数据可能位于不同的字段上)。 30 x 2000 = 60000,即使在每次查询 0.0003 秒的甜蜜查询时间下,这仍然是 18 秒的查询时间(这几乎是我记得的时间)。现在我将查询重建为对一堆主键的大量连接(如果可能),同一份报告在大约 2-3 秒内加载,其中大部分时间用于下载 html。返回的每条记录运行 0-4 个额外查询,具体取决于所需的数据(如果它可以在连接中获取数据,则可能不需要任何数据,这种情况发生的概率为 75%)。因此,同样的 2000 条记录将返回额外的 0-8000 条查询(比 60000 条好得多)。
我会说 while 语句在某些情况下很有用,但正如下面评论中所述,基准测试就是它的全部内容。在我的例子中,联接是更好的选择,但在我网站的其他区域,while 语句更有用。在一个实例中,我有一份报告,其中客户可以请求多个类别来提取并仅返回这些类别的数据。发生的事情是我有一个带有 50-500 个 ID 的 category_id IN(...,...,..,.., etc etc etc) 并且索引会窒息并死在我的怀里我在它的最后时刻拿着它。所以我所做的是将 ID 以 10 个为一组展开,并运行相同的查询 x/10 次,我的结果比以前更快地获取 way 因为索引喜欢处理 10 个 ID,而不是 500 个,因此,由于执行了 while 语句,我发现我的查询有了很大的改进。
最佳答案
如果正确使用索引,那么使用 JOIN 几乎总是更有效。添加重点是因为最佳效率并不总是等于最佳性能。
不过,实际上并没有一个放之四海而皆准的答案;您应该使用 EXPLAIN 分析查询,以确保确实使用了索引,没有使用不必要的临时表等。在某些情况下,条件共同创建只是不能使用索引的查询。在这些情况下,按照您指定的方式将查询分成几部分可能会更快。
如果我在现有项目中遇到这样的代码,我会质疑它:检查查询,想出不同的方式来执行查询,确保已经考虑了这些事情,为或建立一个科学的、有事实支持的案例反对这种做法。确保原始开发人员尽职调查,因为不使用 JOIN 表面上指向糟糕的数据库或查询设计。不过,最后,结果很明显,如果所有的优化和更正仍然导致连接速度比使用查询片段提供的速度慢,那么更快的解决方案将占上风。对标并根据对标结果采取行动;在软件设计中,没有任何情况表明您应该以糟糕的性能为代价来遵守关于您应该做什么或不应该做什么的任意规则。性能最好的方法就是最好的方法。
关于php - JOINS 与 while 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7390849/
我注意到类定义,如果我打开classMyClass,并在不覆盖的情况下添加一些东西我仍然得到了之前定义的原始方法。添加的新语句扩充了现有语句。但是对于方法定义,我仍然想要与类定义相同的行为,但是当我打开defmy_method时似乎,def中的现有语句和end被覆盖了,我需要重写一遍。那么有什么方法可以使方法定义的行为与定义相同,类似于super,但不一定是子类? 最佳答案 我想您正在寻找alias_method:classAalias_method:old_func,:funcdeffuncold_func#similartoca
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
我想从then子句中访问case语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案
我有一个问题。我想从另一个ruby脚本运行一个ruby脚本并捕获它的输出信息,同时让它也输出到屏幕。亚军#!/usr/bin/envrubyprint"Enteryourpassword:"password=gets.chompputs"Hereisyourpassword:#{password}"我运行的脚本文件:开始.rboutput=`runner`putsoutput.match(/Hereisyour(password:.*)/).captures[0].to_s正如您在此处看到的那样,存在问题。在start.rb的第一行,屏幕是空的。我在运行程序中看不到“输入您的密
如何在Ruby的if语句中检查bash命令的返回值(true/false)。我想要这样的东西,if("/usr/bin/fswscell>/dev/null2>&1")has_afs="true"elsehas_afs="false"end它会提示以下错误含义,它总是返回true。(irb):5:warning:stringliteralincondition正确的语法是什么?更新:/usr/bin/fswscell寻找afs安装和运行状态。它会抛出这样的字符串,Thisworkstationbelongstocell如果afs没有运行,命令以状态1退出 最
我最近与一位同事讨论了以下Ruby语法:value=ifa==0"foo"elsifa>42"bar"else"fizz"end我个人并没有看到太多这种逻辑,但我的同事指出,这实际上是一种相当普遍的Rubyism。我试着用谷歌搜索这个主题,但没有找到任何文章、页面或SO问题来讨论它,这让我相信这可能是一种非常实际的技术。然而,另一位同事发现语法令人困惑,而是将上面的逻辑写成这样:ifa==0value="foo"elsifa>42value="bar"elsevalue="fizz"end缺点是value=的重复声明和隐式elsenil的丢失,如果我们想使用它的话。这也感觉它与Ruby
这段代码没有像我预期的那样执行:casewhen->{false}then"why?"else"ThisiswhatIexpect"end#=>"why?"这也不是casewhen->(x){false}then"why?"else"ThisiswhatIexpect"end#=>"why?"第一个then子句在两种情况下都被执行,这意味着我提供给when子句的lambda没有被调用。我知道无论when子句的主题是什么,都应该调用大小写相等运算符===。我想知道当没有为case提供参数时,===的另一边会发生什么。我在想它可能是nil,但它不可能是:->{false}===nil#=>
我需要做这样的事情classUser'User',:foreign_key=>'abuser_id'belongs_to:gameendclassGame['JOINabuse_reportsONusers.id=abuse_reports.abuser_id','JOINgamesONgames.id=abuse_reports.game_id'],:group=>'users.id',:select=>'users.*,count(distinctgames.id)ASgame_count,count(abuse_reports.id)asabuse_report_count',:
请问,一行whileblock的Ruby语法是什么? 最佳答案 例如putsa[i+=1]whilei 关于一行中的whileblock的Ruby语法,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/21712232/