推进ORM - UNION查询

时间:2015-10-26 16:43:27

标签: php mysql union propel

我在网站上查看了相关问题,但没有一个真正回答我的问题。我在使用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个结果),并且使用原始SQL排序超过8秒,则此查询在网站上执行需要20秒。我使用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查询被用在本课程的其他地方时,我不确定它是如何可能的?我怎么能在我的网站上实现这个查询?如果需要,我可以为这个类提供更多代码。

2 个答案:

答案 0 :(得分:0)

在推动博客上有一篇关于它的文章,解释了什么时候使用原始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();

答案 1 :(得分:0)

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

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

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

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

此外,根据您使用的数据库平台,您可以创建物化视图&#39;。

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

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

查询此预先填充的表格将更多更快。