簡體   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