1

次の JOIN クエリがあります。

SELECT
    table1.*, 
    table2.*
FROM 
    Table1 AS table1 
LEFT JOIN 
    Table2 AS table2 
USING 
    (col1)
LEFT JOIN 
    Table3 as table3 
USING 
    (col1) 
WHERE 
    3963.191 * 
    ACOS(
    (SIN(PI() * $usersLatitude / 180) * SIN(PI() * table3.latitude / 180)) 
    +
    (COS(PI() * $usersLatitude / 180) * COS(PI() * table3.latitude / 180) * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180))
    ) <= 10 
AND 
    table1.col1 != '1' 
AND 
    table1.col2 LIKE 'A' 
AND 
    (table1.col3 LIKE 'X' OR table1.col3 LIKE 'X-Y') 
AND 
    (table2.col4 = 'Y' OR table2.col5 = 'Y') 

0.15 秒未満で実行されます。

ただし、単純に追加すると:

ORDER BY 
    table1.col6 DESC 

3 秒以上で実行されます。

で使用されるを含め、クエリ内のすべての列にインデックスが付けられます。table1.col6ORDER BY

この解決策を試しましたが、うまくいきませんでした。

このクエリを で高速に実行するにはどうすればよいですかORDER BY


編集:

EXPLAIN EXTENDED なし の結果ORDER BY:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  table1  ALL PRIMARY,col2,col3   NULL    NULL    NULL    140101  72.61   Using where
1   SIMPLE  table2  eq_ref  PRIMARY,col4,col5   PRIMARY 4   table1.col1 1   100 Using where
1   SIMPLE  table3  eq_ref  PRIMARY PRIMARY 4   table1.col1 1   100 Using where

EXPLAIN EXTENDED WITH の結果ORDER BY:

id  select_type table   type    possible_keys   key key_len ref rows    filtered    Extra
1   SIMPLE  table1  ALL PRIMARY,col2,col3   NULL    NULL    NULL    140101  72.61   Using where; Using filesort
1   SIMPLE  table2  eq_ref  PRIMARY,col4,col5   PRIMARY 4   table1.col1 1   100 Using where
1   SIMPLE  table3  eq_ref  PRIMARY PRIMARY 4   table1.col1 1   100 Using where

編集2:

クエリ内のすべての列のデータ型 (要求に応じて):

col1: int(11)
col2: char(1)
col3: varchar(3)
col4: char(1)
col5: char(1)
col6: int(11)
latitude: varchar(25)
longitude: varchar(25)

3 つのテーブル (table1、table2、および table3) はすべてMyISAMです。

4

5 に答える 5

1

これは解決策ではありませんが、役立つ可能性があります。「*」を使用して必要な列を指定することは避け、明示的に指定してください。*を使用してすべての列を指定すると、MySQLはデータを並べ替えるときにデータをシャントする作業を増やす必要があるため、ファイルの並べ替えを行う可能性が高くなりますが、これは時間がかかります。

また、インデックス作成は、MySQLがデータを並べ替えるのにほとんどまたはまったく影響を与えませんが、BTREEインデックスを使用していることを確認する必要があります。これは、比較的適切な順序で保持される可能性が高いためです。

最悪の場合、MySQLのマニュアルで、ORDER BYの最適化についてまだ読んでいない場合は、その内容を読んでおくとよいでしょう。当てはまるものは何も見えませんが、足りないものが見えるかもしれません。

于 2012-11-22T17:37:50.320 に答える
1

これを回避するために私が考えることができる唯一の他の方法は、テーブルを変更して順序をデフォルトに設定しorder by、クエリから一緒に削除することです。

http://dev.mysql.com/doc/refman/5.1/en/alter-table.html

于 2012-11-22T18:05:57.193 に答える
0

私の他の回答は別として、既存のクエリをselect内にラップしてから、結果を並べ替えます。クエリの別のオプションは次のとおりです...私の解釈が間違っている場合は修正してください。

テーブル 2 に対して LEFT-JOIN を実行していますが、Col4 または Col5 = 'Y' が必要であるため、where 句のために INNER JOIN (レコードは Table1 AND Table2 に存在する必要があります) を示しています。

同様に、テーブル 3 をテーブル 1 に結合しましたが、距離を 10 以下に制限しているため、LEFT-JOIN は WHERE の一部であり、REQUIRED を示しているため正確ではありません。

したがって、私の修正されたクエリを以下に示します。基本的に、「WHERE」コンポーネントをそれぞれのテーブル JOIN コマンドに移動しました。本当に LEFT-JOIN として持つつもりで、すべての Table 1 レコードを Table2/Table3 レコードに関係なくしたい場合は、単純にこれらを LEFT JOIN に変更できます。

SELECT STRAIGHT_JOIN
      T1.*, 
      T2.*
   FROM 
      Table1 AS T1
         JOIN Table2 AS T2
            ON T1.Col1 = T2.Col1
            AND ( T2.Col4 = 'Y' OR T2.Col5 = 'Y' )
         JOIN Table3 as T3
            ON T1.Col1 = T3.Col1
            AND 3963.191 
               * ACOS(  (SIN(PI() * $usersLatitude / 180) * SIN(PI() * T3.latitude / 180)) 
                                + (  COS(PI() * $usersLatitude / 180) * COS(PI() * T3.latitude / 180) 
                                   * COS(PI() * table3.longitude / 180 - PI() * 37.1092162 / 180)
                        )   
                     ) <= 10 
   WHERE
          T1.Col2 LIKE 'A'
      AND ( T1.col3 LIKE 'X' OR T1.col3 LIKE 'X-Y') 
      AND T1.Col1 != '1'
   ORDER BY
      T1.Col6

order by 句を直接適用する場合は、テーブル 1 のインデックスに列 6 を追加します。

On Table 1, I would have an index on ( Col2, Col3, Col1, Col6 )
On Table 2 on ( Col1, Col4, Col5 )
On Table 3 on ( Col1 )   <-- assume already had this.
于 2012-11-22T22:05:03.083 に答える
0

LIKEワイルドカード以外の値に対して s を実行しているのはなぜですか? それはプランナーをより悲観的にするでしょう。しかし、ほとんどの場合、クエリ プランナーが表示しているものを確認する必要があります。

また、ANALYZE最近テーブルで何かをしましたか? 行の統計がオフの場合、プランナは不適切な選択を行います。

于 2012-11-23T03:56:35.363 に答える
0

あなたのクエリがあなたが示したのと同じくらい速いなら、かなり小さなデータセットを返していると思います。その場合は、そのままラップして、ORDER BY OUTIDE を次のように配置します...

select
      PreQuery.*
   from
      ( Your Entire Query Without the order by clause ) as PreQuery
   order by
      PreQuery.Col6 Desc

このように、外側のクエリは既存のインデックスとは関係なく、データを返すだけです...その結果には、生の結果ごとに適用される順序があります。

それが解決することを願っています。

于 2012-11-22T18:57:03.773 に答える