3

テーブルの各行でストアド関数を実行し、最初の 10 行を返す前に、関数の結果によって行を並べ替えるクエリが MySQL にあります。

SELECT rowId, MyFunction(x, y, constX, constY) AS funResult
FROM myTable
ORDER BY funResult DESC
LIMIT 10

問題は、10,000 行のテーブルで実行するのに数秒かかり、遅すぎることです。関数の結果は、PHP によって指定され、クエリが実行されるたびに異なる定数を使用するため、計算してテーブルの別の行として格納することはできません。

ORDER BY funResult DESC LIMIT 10削除すると、クエリが 0.01 秒未満で実行されるため、関数自体の速度は問題になりません。

問題は行のソートに違いありません - 最初の 10 行だけが必要であるという事実を考慮して、これをより速く行う方法はありますか?

アップデート

使用されている単純化された関数は、各行と指定されたポイントの間の距離を計算します (LAT_B と LON_B はクエリに依存する定数です)。

CREATE FUNCTION MyFunction(LAT_A float, LON_A float, LAT_B float, LON_B float)
RETURNS double
DETERMINISTIC
BEGIN

DECLARE tempCalc DOUBLE;
SET tempCalc = 3956 * 2 * ASIN(SQRT( POWER(SIN((LAT_A -abs( LAT_B)) * pi()/180 / 2),2)    
    + COS(LAT_A * pi()/180 ) * COS( abs(LAT_B) *  pi()/180)
    * POWER(SIN((LON_A - LON_B)
    * pi()/180 / 2), 2) ));

RETURN tempCalc;

END
4

5 に答える 5

3

オプション:

  1. ストアド プロシージャの定義/ロジック内に並べ替えを組み込みます。ストアド プロシージャ内で呼び出し元の SQL を選択する場合は、そこで並べ替えと制限を実行します。- これは、ストアド プロシージャで 10,000 行を生成するのではなく、並べ替えるだけであることを意味します。また、テーブルにインデックスがある場合、SQL select 内の元の並べ替えははるかに高速になる可能性があります。

  2. テーブル内でインデックス作成が使用されていることを確認します。- インデックスを使用すると、テーブルで選択するときに並べ替えがより速く実行されます。

関数の定義を提供してください。追加の支援が容易になります。

最後に、後で行うのではなく、関数内で order by と limit を直接移動してみてください。関数は、10 個の結果を直接並べ替えてすぐに返すことができます。必要に応じて、2 つの関数を作成します。1 つは完全な結果を返すもので、もう 1 つはそれらを限定して並べ替えて返すものです。

アップデート:

関数を見た後、計算された値で注文しようとしていることが明らかになります。以下にも記載されているように、計算値による順序付けは非常に遅くなります。

結果の最終的な順序付けを高速化するために、col1 または col2 に基づいてデータを「事前処理/順序付け」する方法を考えようとしています。col1 と col2 がテーブルの列であり、funResult がグラフ化できる数学関数である場合、2 つのうちの 1 つが関数の戻り値により大きな影響を与えます....

最後に、col1 と col2 が myTable の列である場合、ストアド関数を使用する必要はありませんが、クエリを実行できますが、これは大きな違いにはなりません...主な問題は、計算関数による順序付けです:

SELECT rowId, ((col1-INPUT_CONST)*2)+(col2*3) AS funResult
FROM myTable
ORDER BY funResult DESC
LIMIT 10

更新 2:

距離を計算するソートの問題を掘り下げた後、これは以下のリンクで非常に効率的に質問され、解決されていることがわかりました。計算値によるソートに関しては、計算値によるソートは本質的に遅いためです。追加のヘルプについては、次の 2 つのリンクを参照してください。

最後に、あなたの答えに最も近いのはこれです: https://stackoverflow.com/a/4180065/1688441

于 2013-04-29T10:55:15.147 に答える
1

あなたの問題、関数の実行にかかる時間だと思います。このクエリを実行すると:

SELECT rowId, MyFunction(col1, col2, constant) AS funResult
FROM myTable
LIMIT 10

データベースは次のことを行う必要があります。

  • 10行の関数結果を計算します
  • これらの 10 行を返します

対照的に、次のクエリを実行すると:

   SELECT rowId, MyFunction(col1, col2, constant) AS funResult
   FROM myTable
   ORDER BY funResult DESC
   LIMIT 10

データベースは

  • テーブル内の 10000 行すべての関数結果を計算する
  • 10000 行を並べ替える
  • 最初の 10 行を返す

したがって、関数がボトルネックであるかどうかを実際に知るには、両方のクエリの 10000 行すべての関数の結果を実際に計算し、違いが持続するかどうかを確認する必要があります。

于 2013-04-29T11:10:25.583 に答える
1

これを行うには、実際にはmysqlでかなり高速です

select * from database order by 3956 * 2 * ASIN(SQRT( POWER(SIN((LAT_A -abs( LAT_B)) * pi()/180 / 2),2) + COS(LAT_A * pi()/180 ) * COS( abs(LAT_B) * pi()/180) * POWER(SIN((LON_A - LON_B) * pi()/180 / 2), 2) ));

カスタム関数で注文するよりも。

それは醜いですが、はるかに高速です。

それについて説明してみてください。何らかの理由で、mysql は、関連する関数がある場合は一時テーブルを使用しますが、数学だけがある場合は使用しません。

于 2014-04-30T17:26:56.850 に答える
0

これを試して

  SELECT rowId, MyFunction(col1, col2, constant) AS funResult
  FROM myTable
  ORDER BY MyFunction(col1, col2, constant)  DESC
  LIMIT 10
于 2013-04-29T10:54:15.993 に答える