2015-10-26 2 views
1

J'ai regardé des questions connexes à ce sujet sur le site mais aucun d'entre eux ne répond vraiment à ma question. Je les déclarations suivantes dans un site Web en utilisant Propel:Propel ORM - UNION requêtes

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

Cependant, cette requête prend un bon 20 secondes pour exécuter sur le site si le tri par ClosedCallsOnly (donc près de 50 000 résultats) et plus de 8 secondes si vous utilisez SQL brut . Je l'ai optimisé à la requête suivante, en utilisant UNION déclarations:

(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) 

temps d'exécution de cette instruction améliore à peu près 8x qui est vraiment bon, mais malheureusement, je ne suis pas sûr de savoir comment traduire à une requête Propel. En regardant d'autres questions, il semble que l'utilisation de UNION dans Propel n'est pas possible. Je sais que l'utilisation d'instructions SQL est possible dans Propel mais comme les requêtes Propel sont utilisées partout ailleurs dans cette classe, je ne suis pas sûr de savoir comment cela serait possible? Comment pourrais-je implémenter cette requête sur mon site? Si nécessaire, je peux fournir plus de code pour cette classe.

+0

Parfois, il suffit d'écrire du SQL brut, en particulier lors de l'optimisation de requêtes de ce type. – Shelvacu

Répondre

0

Il y a un article à ce sujet sur le blog de propel, expliquant quand il est plus intéressant d'utiliser SQL brut plutôt que l'API de requête, et votre cas semble définitivement faire l'affaire (beaucoup de jointures). http://propelorm.org/blog/2011/02/02/how-can-i-write-this-query-using-an-orm-.html

Voici une de l'utilisation présentée cas:.

« Cette requête est non orientée objet, il est purement relationnel, donc il n'a pas besoin d'un mapping objet-relationnel La meilleure façon pour exécuter cette requête dans un ORM est de sauter l'ORM et utiliser PDO directement: »

$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

ce que je l'ai fait dans cette situation était de créer une vue autour votre grande requête.

Ensuite, vous pouvez créer un modèle ReadOnly Propel dans votre schema.xml

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

Les modèles générés pour cette classe ne sera pas une méthode de sauvegarde(), je crois.

En outre, selon la plate-forme de base de données que vous utilisez, vous pouvez créer une "vue matérialisée.

Oracle a ce genre de chose construite, mais MySQL ne fonctionne pas.

Vous pouvez créer une procédure stockée dans MySQL cependant, que passe toutes les heures et insère les données de votre union dans une table.

En interrogeant ce tableau pré-rempli sera beaucoup plus rapidement.