为什么我的mysql查询工作缓慢?

时间:2015-09-17 11:32:26

标签: php mysql join max

我有一个查询从db获取第二高日期的记录。我的查询运行良好,但执行时间过长。如何快速执行查询。

3 个答案:

答案 0 :(得分:2)

我将采取与其他人不同的方式......我是否遗漏了一些内容,或者除了明显的索引优化之外,所有联接都在查找的主键上 - 您的标准是否准确? / p>

这就是我的意思......你最后的WHERE条款..

   WHERE
         r.client_id IN ( SELECT opinion_id 
                             FROM pacra_client_opinion_relations
                            WHERE client_id = 50 )

您要求CLIENT_ID位于OPINION_ID的选择结果中,但仅查找client_ID = 50的意见.Opinion_id的上下文是什么。

从您的表格中对客户与意见进行澄清" pacra_client_opinion_relations"让我们看下面的样本数据

Opinion_ID    Client_ID   Other...
1             28          ...
2             35          ...
3             50          ...
4             2           ...
5             50          ...
6             6           ...
7             50          ...
8             4           ...

如果您的查询是client_id = 50的所有OPINION_ID,您将返回OPINION_ID #s 3,5和7.由于您的where子句要求选择意见中的CLIENT_ID,您现在正在抓取客户端3的数据, 5和7并没有与你最初开始关注的客户#50有关。

另外......如果您只查找来自" Client_ID = 50"的内容,那么您之前的查询尝试将SECOND发送到最近的通知日期,那么您正在查询所有客户端。如果为" Client_ID = 50"添加where子句,那么您将只获得那些而不是所有客户的第二次到最近通知。

澄清MAX()小于内部MAX()。来自评级的Ex数据,您将获得以下内容......

og_ratings (assuming this data is pre-sorted per client for sample purposes)
client_id  notification_date
13         Sep 5      <- You want THIS entry if it was client 13 included
13         Sep 14     <- Most recent for client 13
28         Sep 1
28         Sep 8
28         Sep 10     <- You want THIS entry if client 28 included
28         Sep 11     <- Most recent for client 28
29         Sep 4      <- You want THIS entry if client 29 included
29         Sep 11     <- Most recent for client 29
43         Sep 16     <- Most recent for client 43 and no prior, 
                         this would never show as only one entry for client
50         Sep 2
50         Sep 9
50         Sep 12     <- You want THIS entry for client 50
50         Sep 15     <- Most recent for client 50

根据样本数据,你会得到......不同的客户可能会有明显不同的第二个和最新的日期

client_id  notification_date
13         Sep 5
28         Sep 10
29         Sep 4 
50         Sep 12

如果您在OUTERMOST查询中所关心的只是客户端50,并且您的实际数据有数百个客户端(甚至数千个客户端),那么您正在查询所有客户端。您可以通过...

专门为客户端50限制内部查询
 og_ratings r INNER JOIN (
    SELECT 
      client_id, 
      max(notification_date) notification_2nd_date
   FROM 
      og_ratings
   WHERE
      (client_id, notification_date) 
         NOT IN ( SELECT client_id, max(notification_date)
                     FROM og_ratings 
                     GROUP BY client_id )
   GROUP BY 
      client_id
   ORDER BY
      client_id DESC

可以调整为......

 og_ratings r INNER JOIN (
    SELECT 
      client_id, 
      max(notification_date) notification_2nd_date
   FROM 
      og_ratings
   WHERE
      client_id = 50    <--- ADDED TO WHERE CLAUSE for CLIENT 50 ONLY
      AND (client_id, notification_date) 
         NOT IN ( SELECT client_id, max(notification_date)
                     FROM og_ratings 
                     WHERE client_id = 50    <--- ADDED HERE TOO FOR CLIENT 50
                     GROUP BY client_id )
   GROUP BY 
      client_id
   ORDER BY
      client_id DESC

并且它只返回客户50的所有记录与所有客户的日期

client_id  notification_date
50         Sep 12

最后,在提供MySQL查询的很多时候,我提供了使用关键字STRAIGHT_JOIN。这基本上告诉MySQL按照你告诉它的顺序进行查询...有时候(例如你的情况),你有一堆查找表,它可能会试着为你考虑并首先使用查找表记录计数(或者是什么/但是)它应用查询。

SELECT STRAIGHT_JOIN ...查询的其余部分

如果我对我的假设是准确的,那么也可以进行更简化的查询,我只是想解释一下我认为有问题的不同部分......最后,正如你看到的样本数据,如果你可以准备关于这个和未来的样本数据以及你想要得到的东西可能有所帮助...

答案 1 :(得分:0)

下面的字段应编入索引以获得性能 -

Table : og_ratings

notification_date
pacra_action
pacra_outlook
pacra_lterm
pacra_sterm

您可以尝试使用个人或综合索引来获得更好的效果。

如果您显示所有包含索引详细信息的表结构,那么可以更好地帮助您。

创建索引的更新:

alter table og_ratings 
add index idx_pacra_action(pacra_action), 
add index idx_pacra_outlook(pacra_outlook), 
add index idx_pacra_lterm(pacra_lterm), 
add index idx_pacra_sterm(pacra_sterm);
由于查询逻辑发生变化,

第二次编辑:

实际上你的查询在逻辑上是不正确的,因为你想在where (client_id, notification_date) not in (SELECT client_id, MAX(notification_date) FROM og_ratings GROUP BY client_id)

之类的子句中传递2个参数

因此,请检查以下查询是否能为您提供所需的结果并且应该快速 -

SELECT r.client_id,c.id,t.id,a.id,o.id,c.name AS opinion, r.notification_date, t.title AS ttitle,a.title AS atitle,o.title AS otitle, l.title AS ltitle, s.title AS stitle, r.opinion_id, pc.id, r.pr_client_id AS pr_client, pc.address, pc.liaison_one, city.id, pc.head_office_id, city.city, pc.title AS cname 
FROM (SELECT a.client_id, a.notification_date, a.rating_type_id, a.pacra_action, a.pacra_outlook, a.pacra_lterm, a.pacra_sterm, a.opinion_id, a.pr_client_id 
FROM (SELECT t.client_id, t.notification_date, t.rating_type_id, t.pacra_action, t.pacra_outlook, t.pacra_lterm, t.pacra_sterm, pr.opinion_id, pr.client_id AS pr_client_id, 
               CASE 
                 WHEN @category != t.client_id THEN @rownum := 1 
                 ELSE @rownum := @rownum + 1 
               END AS rank,
               @category := t.client_id AS var_category
          FROM og_ratings t
          JOIN pacra_client_opinion_relations pr ON pr.opinion_id = r.client_id 
          JOIN (SELECT @rownum := NULL, @category := '') r 
          WHERE pr.client_id = 50
          ORDER BY t.client_id,t.notification_date DESC) a
      WHERE x.rank=2) r 
LEFT JOIN og_companies c ON r.client_id = c.id 
LEFT JOIN og_rating_types t ON r.rating_type_id = t.id 
LEFT JOIN og_actions a ON r.pacra_action = a.id 
LEFT JOIN og_outlooks o ON r.pacra_outlook = o.id 
LEFT JOIN og_lterms l ON r.pacra_lterm = l.id 
LEFT JOIN og_sterms s ON r.pacra_sterm = s.id 
LEFT JOIN pacra_clients pc ON pc.id = r.pr_client_id 
LEFT JOIN city ON city.id = pc.head_office_id 

由于我没有执行此查询,因此如果您遇到任何语法错误等,那么您可以创建一个sqlfiddle以便我可以更正它。

答案 2 :(得分:0)

为参考字段添加索引我的意思是ON部分中的列r.client_id, c.id

  LEFT JOIN og_companies c ON r.client_id = c.id
  LEFT JOIN og_rating_types t ON r.rating_type_id = t.id
  LEFT JOIN og_actions a ON r.pacra_action = a.id
  LEFT JOIN og_outlooks o ON r.pacra_outlook = o.id
  LEFT JOIN og_lterms l ON r.pacra_lterm = l.id
  LEFT JOIN og_sterms s ON r.pacra_sterm = s.id
  LEFT JOIN pacra_client_opinion_relations pr ON pr.opinion_id = c.id
  LEFT JOIN pacra_clients pc ON pc.id = pr.client_id
  LEFT JOIN city ON city.id = pc.head_office_id

那么如何在mysql上添加索引?

SQL&GT;&GT; ALTER TABLE your_table_name ADD INDEX (your_column_name);

另外,为了获得更好的性能,您的连接列应该具有相同的结构。例如,如果你的column_1是int(11),那么unsigned的另一面应该相同。

  
      
  • 确保您拥有属于表连接的所有列的索引
  •   
  • 确保您在过滤器中使用的任何列上都有索引
  •   
  • 明确定义主键明确定义外键关系
  •   
  • 对于大型数据集,请使用表分区将列定义为NOT NULL尽可能
  •   

http://kb.tableau.com/articles/knowledgebase/database-query-performance