2009-07-31 10 views
1

私はデータベースから場所(都道府県)を選択しています。問題は、クエリが少し遅く実行されていると私はそれをスピードアップする方法がわからないということです。例えば:私は(代わりにコードでこれを行うには理由がありますしない限り)データベースは、場所のかわいい、連結バージョンを返すようにしたいのでどのようにこのSELECT CONCAT/GROUP BYクエリを高速化できますか?

SELECT CONCAT_WS(', ', city, state) as location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE city='New York' AND state='NY' 
GROUP BY location 

は、場所を問わずにCONCATがあるようになるだろう。たとえば、「New York、NY」と入力します。実際には、第3列がミックス(郵便番号)にスローされることがあります。私はMySQLで動作しています。

このクエリを最適化するにはどうすればよいでしょうか?

また、副次的な質問として、「DISTINCT」を追加するとクエリが遅くなりますか?たとえば、次のように

SELECT DISTINCT CONCAT_WS(', ', city, state) as location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE city='New York' AND state='NY' 
GROUP BY location 

(私は現在、今これをやっているが、この質問をする過程で、私はDISTINCTが原因GROUP BY句に必要ではなかったことに気づき、それが不要であるため、私は疑問に思う、しかし、何か相違があっても、質問をスピードアップするためにボートを揺らすのが苦労しなければならないのですか?)

編集:都市、州、郵便番号のインデックスは既にあります。それらの組み合わせ(都市、郵便番号、州/郵便番号のみ)

+1

使用、それはメイン減速何をお届けしますポイント – dusoft

答えて

0

このようなクエリを最適に最適化する方法の1つは、これらの列をインデックス列として設定することです。そうすれば、ツリーやハッシュに基づいて簡単にソート/グループ化できます。また、文字列の連結にもいくつかの意味があります。

+0

私は既に列のインデックスを取得しました。 db内ではなくコード内の文字列を連結する方が良いと思いますか? –

4

(state, city)に複合インデックスを作成し、このようクエリを書き直す:しかし、このクエリはまだ必要になります

SELECT 'New York, NY' AS location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE state='NY' 
     AND city='New York' 

:これは非常に照会のためにあなたがGROUP BY句を省略することが

SELECT CONCAT_WS(', ', city, state) AS location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE state='NY' 
     AND city='New York' 
GROUP BY 
     state, city 

は注意それ:

SELECT CONCAT_WS(', ', city, state) AS location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE state='NY' 
GROUP BY 
     state, city 
+0

複数の列をGROUP BYすると、GROUP BYの位置と同じ論理効果がありますか? –

+0

はい、本当に奇妙なケースを除きます(例えば、 'state = 'New York、NY'、city = ''') – Quassnoi

+0

私のジオコーダが動作する方法を考えれば、コンマがどちらの州または都市(「、」は2つのトークンの間の厳しい区切り文字であることを前提としています)。それは私にはかなり良いと思う。 –

0

"city"フィールドにインデックスを追加する「状態」が役立ちます。

また、MySQLのバージョン、テーブルエンジンおよびその他のパラメータで、各フィールドのカーディナリティ(個別の値の数)に応じて、WHERE句を反転するとクエリの実行時間に影響する場合があります。私は試してみる:

2

これは面白いですが、ほとんどの人がデータベースを持っているすべての問題は、スピードでありストレージ要件ではありません。これはあなたに何かを教えてくれるはずです:-)

私はこれまでにこのような問題を抱えていました。これは何度も言いました。私たちがそれらを修正するために見つけた最良の方法は、挿入/更新トリガです(私はMySQLにこれらがあると仮定しています)。

別の列を作成してpretty_city_state(または何でも)を呼び出し、行を挿入または更新するたびにcityとstateからトリガーを移入させます。次に、その上に索引を作成します。

これは、データベースの行が一般的にはから(特にこの場合)よりも多く読み取られるという事実を利用しています。書き込み時にその列を評価することで、読み込み(おそらく数百万回)ではなく、書き込み(数千回)全体でコストが負担されます。また、それが書かれているのはでなければなりません。単にpretty_city_stateが都市または州が変わるときだけ変わるからです。あなたが選択するたびにコンカットを行うなら、あなたは努力を浪費しています。

差を測定してみてください - トリガーの最小コストで選択項目が悲鳴を上げることがわかります(データベース内のすべての都市と州がいったん消滅した場合、その費用は完全に消滅します)

そして、はい、私は、これは3NFを壊す知っているそれは、パフォーマンス上の理由のためにそうすることを完全に受け入れますあなたがやっていることを知っていれば

あなたのクエリを行うことができるように:。。

SELECT pretty_city_state as location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE city='New York' AND state='NY' 
GROUP BY pretty_city_state 

または、多分速く(対策、推測していない)クエリを開始する前に、都市と状態を連結することができた場合:クエリの前にEXPLAIN

SELECT pretty_city_state as location, AVG(latitude), AVG(longitude) 
FROM places 
WHERE pretty_city_state ='New York, NY' 
GROUP BY pretty_city_state 
+0

問題は、何が尋ねられたかによって、連結されるものを時々変更するということです。つまり、ユーザーが郵便番号を含まない場合、私たちは郵便番号を返信しません。もしそうなら、私たちはします。複数のCONCAT行を作成する必要があると思いますか? –

+0

はい、間違いなく。ストレージは安価で、CPUの不満はありません。そして、パフォーマンスのために3NFをvioalteすることを決定したら、あなたはすべての道を行くかもしれません:-) – paxdiablo

+0

ボーナスポイント(私は明らかに多少のSQL初心者です)のUPDATEクエリは何ですか? pretty_city_stateを各行に追加します(この列をすでに作成していると仮定して、処理できると思います)。 –

関連する問題