【问题标题】:Mysql not using my indexesMysql 没有使用我的索引
【发布时间】:2009-06-10 01:52:44
【问题描述】:

我正在使用“解释”来查看为什么我的查询会命中数据库中的每一行,但我不明白为什么会这样。

有人可以看一下并提示我缺少什么吗?

我的数据库是 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

【问题讨论】:

    标签: php mysql query-optimization


    【解决方案1】:

    究竟应该如何使用“纬度”上的排序索引来更有效地评估您的 where 子句? ...当在 where 子句的表达式中使用字段时,索引通常不适用。

    此外,在这种情况下,我不确定您甚至可以重写子句以使索引适用,这有点少见。

    附录
    看看你实际上想要做什么,也许你可以在用户坐标周围使用一个固定大小的纬度/经度框,这样你就可以在纬度和经度上使用BETWEEN 子句。然后,您可以保持 ORDER BY 复合体现在的样子,并在最接近其他用户的“x”之后切断。

    那么你可能永远不会注意到匹配实际上是在一个盒子里,而不是你正在考虑的那个圆形半径。

    【讨论】:

    • 你可以保持圆形半径,只在子句之间添加;那么索引应该开始,但圈外的东西仍然被 where 排除在外。
    • goondocks.com/blog/08-01-22/…有一个很好的例子
    【解决方案2】:

    很可能这是因为您正在过滤表达式而不是索引列。

    MySQL 对列的索引,而不是表达式。你有几个选择:

    1. 您能否将表达式归结为一个固定值并将其存储在一列或两列中?

    如果这是不可能的,那么考虑创建一个非常快速的查找表,然后加入它。例如:

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

    因为它将是一个很小的固定宽度表,所以即使使用全表扫描,您也应该能够非常快速地查询它。只需加入反对它以获得您想要的用户。

    (注意:在进行这些长度之前检查性能要求,因为您可能根本不需要它)

    【讨论】:

      【解决方案3】:

      您实际上并没有将任何东西与纬度或经度进行比较。为了使 indes 工作 mysql 需要设置一些影响纬度 =(或 之间等)的东西。

      尝试重写查询,使其读取

      $lat_low 和 $lat_hi 之间的纬度和 $long_low 和 $long_hi 之间的经度

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-19
        • 1970-01-01
        • 1970-01-01
        • 2018-09-16
        • 2020-09-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多