2015-10-26 2 views
1

Я просмотрел связанные с этим вопросы на этом сайте, но никто из них не ответил на мой вопрос. У меня есть следующие инструкции в веб-сайт с помощью Propel:Propel ORM - запросы UNION

$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); 
    } 
} 

Однако этот запрос занимает хорошие 20 секунд, чтобы выполнить на веб-сайте, если сортировать по ClosedCallsOnly (так почти 50000 результатов) и в течение 8 секунд при использовании сырой SQL , Я оптимизировал его следующий запрос, используя 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. Если посмотреть на другие вопросы, кажется, что использование UNION в Propel невозможно. Я знаю, что использование операторов SQL возможно в Propel, но поскольку запросы Propel используются везде в этом классе, я не уверен, как это возможно? Как я могу реализовать этот запрос на своем веб-сайте? При необходимости я могу предоставить больше кода для этого класса.

+0

Иногда вам просто нужно писать исходный SQL, особенно при оптимизации таких больших запросов. – Shelvacu

ответ

0

В блоге Propel есть статья об этом, объясняя, когда более интересно использовать raw sql, а не API запросов, и ваш случай, по-видимому, определенно соответствует счету (много объединений). http://propelorm.org/blog/2011/02/02/how-can-i-write-this-query-using-an-orm-.html

Вот один из представленных прецеденту:.

«Этот запрос не является объектно-ориентированным, это чисто реляционные, так что не нуждается в объектно-реляционного отображения Лучший способ выполнить этот запрос в ОРМ, чтобы пропустить ОРМ и использовать 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(); 
0

То, что я сделал в этой ситуации было создать представление вокруг ваш большой запрос.

Затем вы можете создать модель Propel ReadOnly в вашем schema.xml

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

Модели, созданные для этого класса не будет иметь метод сохранения(), я считаю.

Кроме того, в зависимости от используемой вами платформы базы данных вы можете создать «материализованный вид».

У Oracle есть такой тип встроенных, но MySQL нет.

Вы можете создать хранимую процедуру в MySQL, хотя это выполняется ежечасно и вставляет данные из вашего объединения в таблицу.

Выполнение запроса в этом заполненном столе будет много быстрее.

Смежные вопросы