我有 3 个模型使用单表继承。它们适用于可在我们网站上购买的三种不同类型的商品。这些项目被放置在类别中,因此类别模型具有用于映射三种类型中的每一种的属性。
当使用一个简单的选择来获取所有类别,然后显示它们的名称和类别中每种类型项目的数量时,Doctrine 总共在 549 毫秒内执行了 361 次查询。 (一个用于类别列表,然后一个用于类别中的每种类型。)
所以我开始向查询中添加连接以消除所有额外的查询。它对第一个项目类型运行良好,主查询运行时间为 101.80 毫秒。 (根据 Symfony Profiler 工具栏)
$this->_em->createQueryBuilder()
->select([$alias, 'courses'])
->from($this->_entityName, $alias)
->leftJoin("{$alias}.courses", 'courses');
一旦我添加第二个连接,查询就会减慢到 24050.14 毫秒
$qb = $this->_em->createQueryBuilder()
->select([$alias, 'courses', 'bundles'])
->from($this->_entityName, $alias)
->leftJoin("{$alias}.courses", 'courses')
->leftJoin("{$alias}.bundles", 'bundles');
我什至还没有尝试过第三次连接,担心它只会让服务器崩溃。
真正奇怪的是,如果我使用 Doctrine Query Logging 并获得准确的查询,然后针对我的数据库手动运行它,它运行仅需 0.2 秒。
该表在所有 FK 列和鉴别器列上都有索引。
如有任何建议,我们将不胜感激。谢谢!
编辑:4/3
我必须让分支回到其他问题的工作点才能回到这个问题。
SQL Fiddle with Schema(减去在这种情况下未加载的其他表的 FK):http://sqlfiddle.com/#!2/85051
所以,我有没有连接的页面,它在 820.38 毫秒内进行了 382 次延迟加载查询。当我手动加入而不是依赖延迟加载时,它对 130 的影响是 21159(这只加入了 2 个模型,所以它仍然延迟加载了第三个)
$qb = $this->_em->createQueryBuilder()
->select([$alias, 'courses', 'bundles'])
->from($this->_entityName, $alias)
->leftJoin("{$alias}.courses", 'courses')
->leftJoin("{$alias}.bundles", 'bundles');
这是来自 Symfony 工具栏的查询(20241.26 毫秒)
SELECT
i0_.description AS description0,
i0_.id AS id1,
i0_.name AS name2,
i0_.created_at AS created_at3,
i0_.updated_at AS updated_at4,
i0_.display_order AS display_order5,
i1_.atccode AS atccode6,
i1_.version AS version7,
i1_.description AS description8,
i1_.online_price AS online_price9,
i1_.mail_price AS mail_price10,
i1_.is_featured AS is_featured11,
i1_.code AS code12,
i1_.hours AS hours13,
i1_.summary AS summary14,
i1_.seo_keywords AS seo_keywords15,
i1_.seo_description AS seo_description16,
i1_.asha_code AS asha_code17,
i1_.preview_name AS preview_name18,
i1_.preview_link AS preview_link19,
i1_.preview_type AS preview_type20,
i1_.is_active AS is_active21,
i1_.id AS id22,
i1_.name AS name23,
i1_.created_at AS created_at24,
i1_.updated_at AS updated_at25,
i1_.deleted_at AS deleted_at26,
i1_.goals AS goals27,
i1_.disclosure_statement AS disclosure_statement28,
i1_.embedded_video AS embedded_video29,
i1_.broadcast_chat_link AS broadcast_chat_link30,
i2_.atccode AS atccode31,
i2_.version AS version32,
i2_.description AS description33,
i2_.online_price AS online_price34,
i2_.mail_price AS mail_price35,
i2_.is_featured AS is_featured36,
i2_.code AS code37,
i2_.hours AS hours38,
i2_.summary AS summary39,
i2_.seo_keywords AS seo_keywords40,
i2_.seo_description AS seo_description41,
i2_.asha_code AS asha_code42,
i2_.preview_name AS preview_name43,
i2_.preview_link AS preview_link44,
i2_.preview_type AS preview_type45,
i2_.is_active AS is_active46,
i2_.id AS id47,
i2_.name AS name48,
i2_.created_at AS created_at49,
i2_.updated_at AS updated_at50,
i2_.deleted_at AS deleted_at51,
i0_.created_by AS created_by52,
i0_.updated_by AS updated_by53,
i1_.type AS type54,
i1_.item_format_id AS item_format_id55,
i1_.company_id AS company_id56,
i1_.created_by AS created_by57,
i1_.updated_by AS updated_by58,
i1_.format_video_id AS format_video_id59,
i1_.exam_id AS exam_id60,
i1_.survey_id AS survey_id61,
i1_.royalty_owner_id AS royalty_owner_id62,
i2_.type AS type63,
i2_.item_format_id AS item_format_id64,
i2_.company_id AS company_id65,
i2_.created_by AS created_by66,
i2_.updated_by AS updated_by67
FROM
item_category i0_
LEFT JOIN item_category_assignment i3_ ON i0_.id = i3_.item_category_id
LEFT JOIN item i1_ ON i1_.id = i3_.item_id
AND i1_.type IN ('Product')
AND (
(
i1_.deleted_at IS NULL
OR i1_.deleted_at > '2014-04-03 13:50:45'
)
)
LEFT JOIN item_category_assignment i4_ ON i0_.id = i4_.item_category_id
LEFT JOIN item i2_ ON i2_.id = i4_.item_id
AND i2_.type IN ('Bundle')
AND (
(
i2_.deleted_at IS NULL
OR i2_.deleted_at > '2014-04-03 13:50:45'
)
)
WHERE
i0_.id IN (
'108',
'175',
'100',
'202',
'198',
'203',
'199',
'200',
'201',
'197',
'101',
'98',
'102',
'131',
'105',
'41',
'72',
'64',
'73',
'194',
'195',
'29',
'189',
'139',
'103',
'37',
'99',
'14',
'110',
'193',
'80',
'111',
'68',
'183',
'39',
'71',
'53',
'66',
'178',
'179',
'180',
'176',
'174',
'75',
'17',
'32',
'81',
'181',
'182',
'74',
'104',
'184',
'26',
'49',
'190',
'191',
'36',
'24',
'85',
'30',
'107',
'91',
'90',
'185',
'23',
'196',
'60',
'89',
'21',
'95',
'65',
'28',
'33',
'58',
'187',
'9',
'132',
'12',
'43',
'192',
'5',
'62',
'40',
'87',
'7',
'83',
'27',
'6',
'86',
'10',
'13',
'15',
'70',
'69',
'121',
'67',
'93',
'97',
'92',
'94',
'188',
'177',
'82',
'96',
'42',
'137',
'19',
'11',
'63',
'20',
'51',
'57',
'8',
'22',
'48',
'35',
'4',
'135',
'61',
'186',
'106',
'109',
'88',
'16',
'31',
'34'
)
ORDER BY
i0_.name ASC
及其解释:
1 SIMPLE i0_ ALL PRIMARY 126 Using where; Using filesort ,
1 SIMPLE i3_ ref item_category_id item_category_id 4 cems-staging.i0_.id 6 ,
1 SIMPLE i1_ eq_ref PRIMARY PRIMARY 4 cems-staging.i3_.item_id 1 Using where ,
1 SIMPLE i4_ ref item_category_id item_category_id 4 cems-staging.i0_.id 6 ,
1 SIMPLE i2_ eq_ref PRIMARY PRIMARY 4 cems-staging.i4_.item_id 1 Using where
* PHP *
这是 Items 模型上的映射:
/**
* @var ArrayCollection
* @ORM\ManyToMany(targetEntity="models\Category")
* @ORM\JoinTable(name="item_category_assignment",
* joinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="item_category_id", referencedColumnName="id")}
* )
*/
protected $categories;
以及类别模型上的映射
/**
* @var ArrayCollection
*
* @ORM\ManyToMany(targetEntity="models\Course")
* @ORM\JoinTable(name="item_category_assignment",
* inverseJoinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="item_category_id", referencedColumnName="id")}
* )
*/
protected $courses;
/**
* @var ArrayCollection
*
* @ORM\ManyToMany(targetEntity="models\Bundle", mappedBy="categories", orphanRemoval=true)
* @ORM\JoinTable(name="item_category_assignment",
* inverseJoinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="item_category_id", referencedColumnName="id")}
* )
*/
protected $bundles;
/**
* @var ArrayCollection
*
* @ORM\ManyToMany(targetEntity="models\Package", mappedBy="categories", orphanRemoval=true)
* @ORM\JoinTable(name="item_category_assignment",
* inverseJoinColumns={@ORM\JoinColumn(name="item_id", referencedColumnName="id")},
* joinColumns={@ORM\JoinColumn(name="item_category_id", referencedColumnName="id")}
* )
*/
protected $packages;
最佳答案
对象和属性与行和列之间的区别在这里真的无关紧要。
您正在尝试执行一系列 LEFT JOIN,您可能应该使用 UNION。
请参阅Microsoft's take在 CROSS JOIN 和笛卡尔积上。他们真的总结得很好。
编辑:我认为这回答了“为什么我的第二次加入很慢?”的问题。
您的意思是要问:“请帮助我改进我的 3 模型 Doctrine 查询以在不到 550 毫秒内运行。” ?
关于php - Doctrine 用单表继承连接两个模型,第二个连接变慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22736761/
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类
对于Rails模型,是否可以/建议让一个类的成员不持久保存到数据库中?我想将用户最后选择的类型存储在session变量中。由于我无法从我的模型中设置session变量,我想将值存储在一个“虚拟”类成员中,该成员只是将值传递回Controller。你能有这样的类(class)成员吗? 最佳答案 将非持久属性添加到Rails模型就像任何其他Ruby类一样:classUser扩展解释:在Ruby中,所有实例变量都是私有(private)的,不需要在赋值前定义。attr_accessor创建一个setter和getter方法:classUs