Mysql benim indeksleri kullanılarak değil

3 Cevap php

Ben sorgu benim veritabanında her satır vuruyor neden görüntülemek için 'açıklamak' kullanıyorum, ve bunu neden yaptığını anlamıyorum.

Birisi bir göz atın ve bana eksik ne bir ipucu verebilir misiniz?

Benim veritabanı MyISAM, ve ben Mysql 5.1, PHP5 kullanıyorum

İşte benim tablo:

--
-- 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 ;

İşte benim sorgu:

$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";

Ve nihayet, açıklamak Gözat ...

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

3 Cevap

Bir İFADE ziyade endeksli sütun üzerinde filtreleme çünkü Most likely öyle.

Sütunlar, değil ifadeler MySQL indeksler. Burada birkaç seçenek var:

  1. Eğer sabit bir değer ifade aşağı kaynatın ve bir ya da iki sütun halinde saklayabilirsiniz?

Bu mümkün değilse, o zaman çok hızlı bir arama tablosu oluşturmayı düşünün ve buna karşı katılın. Örneğin:

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

Küçücük bir sabit genişlik tablo olacak, çünkü, hatta tam bir tablo taraması ile çok hızlı bunu sorgulamak gerekir. Sadece istediğiniz kullanıcıları almak için buna karşı katılın.

(Not: Bu uzunlukları gitmeden önce performans gereksinimlerini kontrol, hiç gerek olmayabilir gibi)

Tam olarak nasıl daha verimli nerede maddesini değerlendirmek için 'enlem' sıralanmış bir dizin kullanmak gerekiyordu? Bir alan burada yan tümcesinde bir ifadede kullanıldığı zaman ... endeksler genelde geçerli değildir.

Ayrıca, bu durumda ben bile dizin biraz nadir olduğu, uygulamak yapmak için fıkra yazabilirsiniz emin değilim.

Addendum:
Looking at what you are actually trying to do, maybe you can use a fixed-size lat/long box around the users' coordinate, so that you can use BETWEEN clauses on lat and long. Then you can keep the ORDER BY complex as it is now, and cut-off after the 'x' closest other users.

Sonra maçı yerine düşünen biri dairesel yarıçap daha bir kutu aslında olduğunu fark asla.

Aslında enlem veya boylam şey karşılaştırarak değildir. Indes se bir şey için (vb, arasında veya <>) etki enlem = için mysql NEES çalışması için.

Okur bu yüzden sorguyu yeniden deneyin

NEREDE $ lat_low VE $ lat_hi ve boylam arasındaki $ long_low VE $ long_hi arasındaki enlem