繁体   English   中英

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

[英]Why my mysql query is working slow?

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

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

这就是我的意思......你最后的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 ...查询的其余部分

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

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

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

由于查询逻辑的更改,第二次编辑:

实际上你的查询在逻辑上是不正确的,因为你想要在不在子句中传递2个参数,例如where (client_id, notification_date) not in (SELECT client_id, MAX(notification_date) FROM og_ratings GROUP BY client_id)

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

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,以便我可以纠正它。

向索引字段添加索引我的意思是在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 >> 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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM