2012-03-01 34 views
2

我有一個帶有三個表的數據庫,我需要將第一個表與另外兩個表交叉引用以創建第四個合併信息表。所有表格都有一個通用的字段,這是MSISDN(手機/手機號碼),至少有10位數字。減少MySQL查詢時間(目前運行24小時,但仍在繼續)

表1 - 819248行

表2 - 75308813行

表3 - 17701196行

我想從表1中返回的所有行,並從表2附加某些字段和表3中有一個匹配的MSISDN。 我的查詢現在已經運行了24小時以上,我無法知道這樣的事情需要多長時間。

這種類型的查詢可能是一個常規項目 - 有沒有一種方法來顯着減少查詢時間?

我有索引表2和3與MSISDN和我需要返回的字段。

我的查詢是這樣的:

create TABLE FinishedData 
select 
    Table1.ADDRESS, table1.POSTAL, table1.MOBILE, 
    table1.FIRST, table1.LAST, table1.MID, table1.CARRIER, 
    table1.TOWN, table1.ID, table2.status as 'status1', 
    table2.CurrentNetworkName as 'currentnetwork1', 
    table2.DateChecked as 'datechecked1', table3.Status as 'status2', 
    table3.CurrentNetworkName 'currentnetwork2', 
    table3.DateChecked as 'datechecked2' 
from 
    table1 left join (table2, table3) 
     on (right(table1.MOBILE, 10) = right(table2.MSISDN, 10) 
     AND right(table1.MOBILE,10) = right(table3.MSISDN,10)) 

MySQL是一個64位Windows機器12GB內存和8個邏輯核心3GHz的@上運行。運行查詢時,MySQLd僅使用10%cpu和600MB資源。

任何幫助表示讚賞。

回答

3

終止性能問題與正確功能當你使用這個函數時,MySQL不能使用索引。

我的建議是:

  1. reverse內容MSISDN
  2. 的創建表2和表3中的新領域讓由左功能的加入替換正確的函數。

有了這個小小的改變,MySQL可以通過索引讓你的連接成爲可能。

解釋步驟:

1)創建新的列:

Alter table table2 add column r_MSISDN varchar(200); 
update table2 set r_MSISDN = reverse(MSISDN); 

Alter table table3 add column r_MSISDN varchar(200); 
update table3 set r_MSISDN = reverse(MSISDN); 

2)新加盟:

... 
from 
    table1 left join (table2, table3) 
     on (right(table1.MOBILE, 10) = left(table2.r_MSISDN, 10) 
     AND right(table1.MOBILE,10) = left(table3.r_MSISDN,10)) 
+0

感謝danihp - 它似乎是導致問題的「正確」功能。我從你的帖子中猜測'左'沒有相同的問題。我會嘗試使用標準化數據創建新列,然後避免使用「正確」或「左」 - 這樣可以避免將來如果添加更多內容,我將不得不再次反向數據。我正在使用你的代碼來創建新的列,但我正在對它進行規範化,而不是顛倒數據。 – 2012-03-01 10:42:10

1

RIGHT是一個函數。在where子句中使用函數意味着MySQL(也可能是任何數據庫)不能使用索引,因爲它必須在比較之前計算每行的函數返回的值。

如果您希望更快地進行此查詢,請考慮將MSISDN存儲爲規範化格式,並使用=運算符進行比較。

現在我不知道什麼MSISDN號碼看起來像。如果它是一個固定寬度的數字,那麼你的工作很容易。如果它包含分隔符(空格/連字符)並且分隔符僅用於提供可讀性,則應在將它們存儲到數據庫之前將其刪除。如果前10個字符很重要,剩餘字符可選,則可以考慮將前10個字符和剩餘字符存儲在不同的列中。

+0

謝謝薩爾曼。我使用danihp建議的代碼創建新列,但是將數據標準化而不是反轉。無論如何,我認爲我本來應該這樣做,所以這就是我將要使用的解決方案。這也意味着將來我可以規範化更多的MSISDN並針對這些進行查詢。 – 2012-03-01 10:45:14

1

正如其他人已經提到的,問題是right函數不允許使用任何索引。

簡而言之,您對table1中每行的當前查詢都會對table2進行全面掃描,並且對於每個匹配,都會對table3進行全面掃描。考慮到你在table2和table3中有多少行,你有很大的機會在查詢完成之前看到世界。

另一個問題是查詢啓動了一個巨大的事務,它應該能夠像MySQL認爲的那樣回滾,並且您可能會考慮隔離級別。

雖然我不會改變當前表格。我將創建具有所需列的table2和table3的子表,並將table2.MSISDN(10)作爲table2 copy(右(table3.MSISDN,10)中的單獨索引列)添加到table3副本中。

然後,您可以對副本執行LEFT JOIN,或者將副本減少到與table1中的任何內容匹配的行,然後執行LEFT JOIN。

+0

謝謝你的幫助newtover。我在發佈之前開始創建新列,以便完成此操作並檢查它是否有效。因爲我將來可能再次引用table2和table3,所以我可能需要不同的列,所以我會盡量避免每次創建新表。我沒有足夠的代表投票迴應您的回覆 - 抱歉!我需要15個代表或更多。 – 2012-03-01 10:46:58