0

次の SQL を最適化して、サーバーの読み込みを高速化し、使用率を下げる方法を知りたいですか?

米国の郵便番号の半径距離を計算して、特定の郵便番号から 50 マイル (緯度と経度を使用して計算) などの結果を取得し、データベースから他のデータ (他の郵便番号など) を取得する必要があります。 .

結果を取得したら (たとえば、特定の郵便番号から 50 マイル以内に異なる郵便番号の 350 行を取得した場合)、それらを別のクエリに渡して合計行をカウントし、それを単純な 1 つの結果で表示して読み取る必要があります。これが私のクエリの例です:

SELECT count(*)
FROM
( SELECT b.ID, ROUND((acos(sin(3.142/180*32.91336) * sin(3.142/180*z.latitude) + cos(3.142/180*32.91336) * cos(3.142/180*z.latitude) * cos((3.142/180*z.longitude) - (3.142/180*-85.93836))) * 3959),2) AS distance
  FROM zipcode2business.accountants b LEFT JOIN zipcodeworld.storelocator_us z ON b.ZIPCODE = z.ZIP_CODE
  WHERE z.latitude != 32.91336 AND z.longitude != -85.93836
  AND b.STATE='AL'
  HAVING distance between 0 AND 50) 
as total;

正しい結果 ( 350 行 ) が表示されますが、この SQL を実行すると CPU 使用率が高くなるため、最適化された方法で実行する必要があります。このクエリに対して EXPLAIN を実行すると、次のように表示されます。

+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
| id | select_type | table | type   | possible_keys    | key     | key_len | ref                        | rows | Extra                        |
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
| 1 | PRIMARY      | NULL  | NULL   | NULL             | NULL    | NULL    |        NULL                | NULL | Select tables optimized away |
| 2 | DERIVED      | b     | ref    | ZIPCODE,STATE    | STATE   | 4       |                            | 3900 | Using where                  |
| 2 | DERIVED      | z     | eq_ref | PRIMARY,LAT_LONG | PRIMARY | 9       | zipcode2business.b.ZIPCODE | 1    | Using where                  |
+----+-------------+-------+--------+------------------+---------+---------+----------------------------+------+------------------------------+
3 rows in set (0.20 sec)

さて、上記の説明から、EXTRAの「最適化されたテーブルを選択する」は良いことですか?このクエリを実行するための最も完璧な最適化 SQL を 1 つ教えてください。

4

3 に答える 3

1

適切な SQL は問題ないように見えますが、CPU 時間の大部分を計算に費やす必要があります... 最適化には 2 つの方法があります

  • 式を単純化する
  • さらに単純な計算に基づいて、行を早期に除外 (「プルーニング」) します。

現時点では詳細を説明する時間はありませんが、一般的な考え方は次のとおり
です。参照 ZipCode の場所と他の場所からの距離を、安価な (CPU に関する) 計算で概算し、完全な計算のみを行うことです(元のクエリの式よりも優れた式を使用)、50 マイル未満の場所に対して (+ 過小評価の可能性を考慮してわずかな追加)。

距離の推定と枝刈り一度、参照郵便番号の場所から緯度 1 度と経度 1 度に対応する距離をマイル単位で
計算します。これらを MpDLat および MpDLong と呼びます。おそらく、参照位置からのターゲット半径に対応する度の分数値を計算します。これらを Dp50Lat および Dp50Long と呼びます。次に、参照位置に対する緯度と経度の [絶対値の] 差を処理し、一方向 (緯度または経度) でのこの距離が制限を超える場所を除外します。つまり、次のようなもの

WHERE .... (some other condidtions....) 
   AND (abs(z.latitude - 32.91336) * MpDLat) < 50 
   AND (abs(z.longitude + 85.93836) * MpDLong) < 50 
--or, if we got by the Dp50 values
WHERE .... (some other condidtions....) 
   AND (abs(z.latitude - 32.91336)  < Dp50Lat
   AND (abs(z.longitude + 85.93836) < Dp50Long 

距離の計算(容易にフィルタリングされない場所の場合)
必要な精度のレベルによっては、MpD 係数を使用しても問題ない場合があります (距離が 50マイル、米国本土内)。次に、距離は次のように計算されます。つまり、... WHERE (z.latitude - 32.91336)^2 + (z.longitude + 85.93836)^2 < 2500 -- 2509 は 50^2

このタイプの近似は許​​容できると思います。道路を経由した距離 (最終的にはこれが望ましいと思われます) が 'as-the-crow-flies' の距離と一致することはめったにないという事実を考慮すると、はるかに大きな誤差が生じるためです。 -) 正確な最悪の場合の精度の損失を計算できます (しかし、繰り返しになりますが、今は時間がありません...)

正確な距離が必要な場合は、元の式よりもわずかに優れた式を使用します。これは、余弦の球面法則から直接導出されたようです。おそらくもっとうまくやれるでしょう。

上記のバリエーション 上記
のアイデアは、さまざまな方法で実装できます。たとえば、一時的な SQL テーブルを使用したり、クエリのさまざまな構成要素を使用したりできます。

于 2009-10-02T05:03:50.753 に答える
0

一時テーブルへの距離計算を選択し、SQL から HAVING を削除してから、2 番目の SELECT WHERE dist <= 50 を実行できます。

これにより、メモリ スペースが節約され、ベース テーブル内の多数のレコードの一時ディスク セグメントにスワップ アウトされる可能性があります。

于 2009-10-08T11:54:16.760 に答える
0

これらすべての計算を SQL サーバー上で行う必要がありますか? 私は通常、データの基本的な CRUD にのみ SQL を使用しようとします。その後、他のすべての計算は SQL の外部で行われます。計算の基にしているデータを取得してから、データを取得しているものを使用して実際の計算を実行することをお勧めします。

于 2009-10-02T03:37:17.040 に答える