0

「explain」を使用して、クエリがデータベースのすべての行にヒットする理由を確認していますが、その理由がわかりません。

誰かが見て、私が欠けているもののヒントを教えてもらえますか?

私のデータベースは MyISAM で、Mysql 5.1、PHP5 を使用しています。

ここに私のテーブルがあります:

--
-- Table structure for table `users`
--

CREATE TABLE IF NOT EXISTS `users` (
  `user_id` bigint(20) NOT NULL auto_increment,
  `name` varchar(40) default NULL,
  `city` varchar(90) default NULL,
  `latitude` float NOT NULL default '0',
  `longitude` float NOT NULL default '0',
  PRIMARY KEY  (`user_id`),
  UNIQUE KEY `name` (`name`),
  KEY `Radius Search` (`latitude`,`longitude`),
  KEY `Radius 2` (`longitude`,`latitude`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=38666 ;

これが私のクエリです:

$query =    
"SELECT
    name, city
FROM
    users
WHERE
    (
        (69.1 * (latitude - " . $user->latitude . ")) * 
        (69.1 * (latitude - " . $user->latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3))
    ) < " . pow($radius, 2) . " 
ORDER BY 
    (
        (69.1 * (latitude - " . $user->latitude . ")) * 
        (69.1 * (latitude - " . $user->latitude . "))
    ) + ( 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3)) * 
        (69.1 * (longitude - " . $user->longitude . ") * COS(" . $user->latitude . " / 57.3))
    ) ASC";

そして最後に、私の説明...

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE  users   ALL     NULL    NULL    NULL    NULL    38665   Using where; Using filesort
4

3 に答える 3

3

where句をより効率的に評価するために、「緯度」でソートされたインデックスをどのように使用することになっていますか? ... フィールドが where 句の式で使用されている場合、通常、インデックスは適用されません。

さらに、この場合、句を書き直してインデックスを適用できるかどうかもわかりませんが、これは少しまれです。

補遺:
実際にやろうとしていることを見ると、BETWEEN緯度と経度の節を使用できるように、ユーザーの座標の周りに固定サイズの緯度/経度ボックスを使用できる可能性があります。その後、コンプレックスをそのままにして、' ' 最も近い他のユーザーのORDER BY後にカットオフすることができます。x

そうすれば、一致が実際には、考慮している円形の半径ではなく、ボックス内にあることに気付かない場合があります。

于 2009-06-10T01:58:17.683 に答える
2

実際には、緯度や経度と何かを比較しているわけではありません。indes が動作するためには、mysql は効果 latitude = (または < > between など) に何かを設定する必要があります。

読み取るようにクエリを書き直してみてください

$lat_low と $lat_hi の間の WHERE 緯度と $long_low と $long_hi の間の経度

于 2009-06-10T02:02:57.127 に答える
2

最も可能性が高いのは、インデックス付きの列ではなく、EXPRESSION でフィルター処理を行っているためです。

式ではなく、列の MySQL インデックス。ここにはいくつかのオプションがあります。

  1. 式を固定値に煮詰めて、1 つまたは 2 つの列に格納できますか?

それが不可能な場合は、非常に高速なルックアップ テーブルを作成し、それに対して結合することを検討してください。例えば:

CREATE TABLE user_loc 
(
    longitude float(n,m) not null, 
    latitude float(n,m) not null, 
    user_id int unsigned not null
);

これは小さな固定幅のテーブルになるため、完全なテーブル スキャンでも非常に高速にクエリを実行できるはずです。それに反対するだけで、必要なユーザーを獲得できます。

(注:まったく必要ない場合があるため、これらの長さに行く前にパフォーマンス要件を確認してください)

于 2009-06-10T02:00:14.167 に答える