【问题标题】:Propel ORM - UNION queries推动 ORM - UNION 查询
【发布时间】:2015-10-26 16:43:26
【问题描述】:

我已经在网站上查看了有关此问题的相关问题,但没有一个真正回答我的问题。我在使用 Propel 的网站中有以下语句:

$query = $query
  ->distinct()
  ->select(Request::getTransferFieldsWithRelations())
  ->leftJoinResponse("Response")
  ->joinWith("Request.SupportStatus SupportStatus")
  ->joinWith("Request.CustomerGroup CustomerGroup", Criteria::LEFT_JOIN)
  ->joinWith("Request.Customer Customer", Criteria::LEFT_JOIN)
  ->joinWith("Request.Site Site", Criteria::LEFT_JOIN)
  ->joinWith("Request.InternalUser InternalUser", Criteria::LEFT_JOIN)
  ->joinWith("Request.User User", Criteria::LEFT_JOIN)
  ->orderBy("CreatedDate", Criteria::ASC);

$conditions = array(
  "and" => array(),
  "or" => array()
);

if(isset($args["QueryText"]) && $args["QueryText"] != "") {
  $query = $query
    ->withColumn("(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE))", "RequestRelevance")
    ->condition('cond1', "(MATCH (Request.Subject, Request.Detail) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE) + MATCH (Response.Response) AGAINST ('" . $args["QueryText"] . "' IN BOOLEAN MODE)) > 0.2")
    ->condition('cond2', 'Request.Id = ?', $args["QueryText"])
    ->where(array('cond1', 'cond2'), 'or')
    ->orderBy("RequestRelevance", Criteria::DESC);
}

if(isset($args["OpenCallsOnly"]) && $args["OpenCallsOnly"] == 1) {
  $query = $query
    ->useSupportStatusQuery()
      ->filterByOutstanding(1)
    ->endUse();
}

if(isset($args["ClosedCallsOnly"]) && $args["ClosedCallsOnly"] == 1) {
  $query = $query
    ->useSupportStatusQuery()
      ->filterByIsClosed(1)
    ->endUse();
}

...

foreach ($conditions as $key => $value) {
  if(!empty($value)){
    $query = $query
      ->where($value, $key);
  }
}

但是,如果按ClosedCallsOnly 排序(接近 50000 个结果),则此查询在网站上执行需要 20 秒,如果使用原始 SQL,则需要超过 8 秒。我已使用UNION 语句将其优化为以下查询:

    (SELECT DISTINCT
requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate"
FROM requests
  LEFT JOIN responses Response ON (requests.requestID=Response.requestID)
  INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID)
  INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID)
  INNER JOIN customers Customer ON (requests.customerID=Customer.customerID)
  INNER JOIN sites Site ON (requests.siteID=Site.siteID)
  LEFT JOIN users InternalUser ON (requests.internal_userID=InternalUser.userID)
  LEFT JOIN users User ON (requests.userID=User.userID)
WHERE ((MATCH (requests.subject, requests.detail) AGAINST ('slow pc' IN BOOLEAN MODE)
  ))
ORDER BY requests.created ASC)
UNION
(SELECT DISTINCT
requests.requestID AS "Id", requests.subject AS "Subject", requests.detail AS "Detail", requests.created AS "CreatedDate", requests.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate"
FROM requests
  LEFT JOIN responses Response ON (requests.requestID=Response.requestID)
  INNER JOIN supportstatus SupportStatus ON (requests.supportstatusID=SupportStatus.supportstatusID)
  INNER JOIN customergroups CustomerGroup ON (requests.customergroupID=CustomerGroup.customergroupID)
  INNER JOIN customers Customer ON (requests.customerID=Customer.customerID)
  INNER JOIN sites Site ON (requests.siteID=Site.siteID)
  LEFT JOIN users InternalUser ON (requests.internal_userID=InternalUser.userID)
  LEFT JOIN users User ON (requests.userID=User.userID)
WHERE (requests.requestID = 'slow pc')
ORDER BY requests.created ASC)
UNION
(SELECT DISTINCT
Request.requestID AS "Id", Request.subject AS "Subject", Request.detail AS "Detail", Request.created AS "CreatedDate", Request.lastresponsedate AS "LastResponseDate", SupportStatus.supportstatusID AS "SupportStatus.Id", SupportStatus.supportstatus AS "SupportStatus.Name", SupportStatus.isnew AS "SupportStatus.IsNew", SupportStatus.isclosed AS "SupportStatus.IsClosed", CustomerGroup.customergroupID AS "CustomerGroup.Id", CustomerGroup.customergroup AS "CustomerGroup.Name", Site.siteID AS "Site.Id", Site.site AS "Site.Name", InternalUser.userID AS "InternalUser.Id", InternalUser.username AS "InternalUser.Username", User.userID AS "User.Id", User.username AS "User.Username", Customer.customerID AS "Customer.Id", Customer.customer AS "Customer.Name", Customer.customergroupID AS "Customer.CustomerGroupId", Customer.rate AS "Customer.Rate"
FROM responses
  LEFT JOIN requests Request ON (Request.requestID=responses.requestID)
  INNER JOIN supportstatus SupportStatus ON (Request.supportstatusID=SupportStatus.supportstatusID)
  INNER JOIN customergroups CustomerGroup ON (Request.customergroupID=CustomerGroup.customergroupID)
  INNER JOIN customers Customer ON (Request.customerID=Customer.customerID)
  INNER JOIN sites Site ON (Request.siteID=Site.siteID)
  LEFT JOIN users InternalUser ON (Request.internal_userID=InternalUser.userID)
  LEFT JOIN users User ON (Request.userID=User.userID)
WHERE ((
  MATCH (responses.response) AGAINST ('slow pc' IN BOOLEAN MODE)))
ORDER BY Request.created ASC)

该语句的执行时间大约提高了 8 倍,这确实很好,但不幸的是,我不确定如何将其转换为 Propel 查询。从查看其他问题来看,似乎在 Propel 中使用 UNION 是不可能的。我知道在 Propel 中使用 SQL 语句是可能的,但是由于 Propel 查询在这个类的其他地方都被使用,我不确定这怎么可能?我怎样才能在我的网站中实现这个查询?如果需要,我可以为这个类提供更多代码。

【问题讨论】:

  • 有时您只需要编写原始 SQL,尤其是在优化此类大型查询时。

标签: php mysql union propel


【解决方案1】:

propel 博客上有一篇关于它的文章,解释了何时使用原始 sql 而不是查询 API 更有趣,您的情况似乎完全符合要求(大量连接)。 http://propelorm.org/blog/2011/02/02/how-can-i-write-this-query-using-an-orm-.html

这是一个展示的用例:

"这个查询不是面向对象的,它是纯关系的,所以它 不需要对象关系映射。最佳执行方式 ORM 中的这个查询是跳过 ORM 并直接使用 PDO:"

$con = Propel::getConnection();
$query = 'SELECT COUNT(t1.user) AS users, t1.choice AS lft, t2.choice AS rgt
  FROM choice t1 iNNER JOIN choice t2 ON (t1.user = t2.user)
  WHERE t1.choice IN (?, ?) AND t2.choice IN (?, ?)
  GROUP BY t1.choice, t2.choice';
$stmt = $con->prepare($query);
$stmt->bindValue(1, 'foo');
$stmt->bindValue(2, 'bar');
$stmt->bindValue(3, 'baz');
$stmt->bindValue(4, 'foz');
$res = $stmt->execute();

【讨论】:

    【解决方案2】:

    在这种情况下,我所做的是围绕您的大型查询创建一个视图。

    然后你可以在你的 schema.xml 中创建一个 Propel ReadOnly 模型

    <table name="my_table" readOnly="true">
    

    我相信为这个类生成的模型不会有 save() 方法。

    此外,根据您使用的数据库平台,您可以创建一个“物化视图”。

    Oracle 内置了这种类型的东西,但 MySQL 没有。

    您可以在 MySQL 中创建一个存储过程,该过程每小时运行一次并将数据从您的联合插入到表中。

    查询这个预先填充的表格会快得多

    【讨论】:

      猜你喜欢
      • 2011-07-01
      • 1970-01-01
      • 2011-04-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-05
      • 2013-09-28
      相关资源
      最近更新 更多