Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何使用多个连接优化慢速查询_Mysql_Performance_Join_Query Optimization - Fatal编程技术网

Mysql 如何使用多个连接优化慢速查询

Mysql 如何使用多个连接优化慢速查询,mysql,performance,join,query-optimization,Mysql,Performance,Join,Query Optimization,我的情况: 该查询搜索了大约90000辆汽车 每次查询都需要很长时间 我已经在所有要联接的字段上建立了索引 如何优化它? 以下是查询: SELECT vehicles.make_id, vehicles.fuel_id, vehicles.body_id, vehicles.transmission_id, vehicles.colour_id, vehicles.mileage, vehicles.vehi

我的情况:

  • 该查询搜索了大约90000辆汽车
  • 每次查询都需要很长时间
  • 我已经在所有要联接的字段上建立了索引
如何优化它?

以下是查询:

SELECT vehicles.make_id,
       vehicles.fuel_id,
       vehicles.body_id,
       vehicles.transmission_id,
       vehicles.colour_id,
       vehicles.mileage,
       vehicles.vehicle_year,
       vehicles.engine_size,
       vehicles.trade_or_private,
       vehicles.doors,
       vehicles.model_id,
       Round(3959 * Acos(Cos(Radians(51.465436)) *
                         Cos(Radians(vehicles.gps_lat)) *
                                           Cos(
                                           Radians(vehicles.gps_lon) - Radians(
                                           -0.296482)) +
                               Sin(
                                      Radians(51.465436)) * Sin(
                               Radians(vehicles.gps_lat)))) AS distance
FROM   vehicles
       INNER JOIN vehicles_makes
         ON vehicles.make_id = vehicles_makes.id
       LEFT JOIN vehicles_models
         ON vehicles.model_id = vehicles_models.id
       LEFT JOIN vehicles_fuel
         ON vehicles.fuel_id = vehicles_fuel.id
       LEFT JOIN vehicles_transmissions
         ON vehicles.transmission_id = vehicles_transmissions.id
       LEFT JOIN vehicles_axles
         ON vehicles.axle_id = vehicles_axles.id
       LEFT JOIN vehicles_sub_years
         ON vehicles.sub_year_id = vehicles_sub_years.id
       INNER JOIN members
         ON vehicles.member_id = members.id
       LEFT JOIN vehicles_categories
         ON vehicles.category_id = vehicles_categories.id
WHERE  vehicles.status = 1
       AND vehicles.date_from < 1330349235
       AND vehicles.date_to > 1330349235
       AND vehicles.type_id = 1
       AND ( vehicles.price >= 0
             AND vehicles.price <= 1000000 )  
解释:

CREATE TABLE IF NOT EXISTS `vehicles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `number_plate` varchar(100) NOT NULL,
  `type_id` int(11) NOT NULL,
  `make_id` int(11) NOT NULL,
  `model_id` int(11) NOT NULL,
  `model_sub_type` varchar(250) NOT NULL,
  `engine_size` decimal(12,1) NOT NULL,
  `vehicle_year` int(11) NOT NULL,
  `sub_year_id` int(11) NOT NULL,
  `mileage` int(11) NOT NULL,
  `fuel_id` int(11) NOT NULL,
  `transmission_id` int(11) NOT NULL,
  `price` decimal(12,2) NOT NULL,
  `trade_or_private` tinyint(4) NOT NULL,
  `postcode` varchar(25) NOT NULL,
  `gps_lat` varchar(50) NOT NULL,
  `gps_lon` varchar(50) NOT NULL,
  `img1` varchar(100) NOT NULL,
  `img2` varchar(100) NOT NULL,
  `img3` varchar(100) NOT NULL,
  `img4` varchar(100) NOT NULL,
  `img5` varchar(100) NOT NULL,
  `img6` varchar(100) NOT NULL,
  `img7` varchar(100) NOT NULL,
  `img8` varchar(100) NOT NULL,
  `img9` varchar(100) NOT NULL,
  `img10` varchar(100) NOT NULL,
  `is_featured` tinyint(4) NOT NULL,
  `body_id` int(11) NOT NULL,
  `colour_id` int(11) NOT NULL,
  `doors` tinyint(4) NOT NULL,
  `axle_id` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  `contents` text NOT NULL,
  `date_created` int(11) NOT NULL,
  `date_edited` int(11) NOT NULL,
  `date_from` int(11) NOT NULL,
  `date_to` int(11) NOT NULL,
  `member_id` int(11) NOT NULL,
  `inactive_id` int(11) NOT NULL,
  `status` tinyint(4) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `type_id` (`type_id`),
  KEY `make_id` (`make_id`),
  KEY `model_id` (`model_id`),
  KEY `fuel_id` (`fuel_id`),
  KEY `transmission_id` (`transmission_id`),
  KEY `body_id` (`body_id`),
  KEY `colour_id` (`colour_id`),
  KEY `axle_id` (`axle_id`),
  KEY `category_id` (`category_id`),
  KEY `vehicle_year` (`vehicle_year`),
  KEY `mileage` (`mileage`),
  KEY `status` (`status`),
  KEY `date_from` (`date_from`),
  KEY `date_to` (`date_to`),
  KEY `trade_or_private` (`trade_or_private`),
  KEY `doors` (`doors`),
  KEY `price` (`price`),
  KEY `engine_size` (`engine_size`),
  KEY `sub_year_id` (`sub_year_id`),
  KEY `member_id` (`member_id`),
  KEY `date_created` (`date_created`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=136237 ;
1   SIMPLE  vehicles    ref     type_id,make_id,status,date_from,date_to,price,mem...   type_id     4   const   85695   Using where
1   SIMPLE  members     index   PRIMARY     PRIMARY     4   NULL    3   Using where; Using index; Using join buffer
1   SIMPLE  vehicles_makes  eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.make_id    1   Using index
1   SIMPLE  vehicles_models     eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.model_id   1   Using index
1   SIMPLE  vehicles_fuel   eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.fuel_id    1   Using index
1   SIMPLE  vehicles_transmissions  eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.transmission_id    1   Using index
1   SIMPLE  vehicles_axles  eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.axle_id    1   Using index
1   SIMPLE  vehicles_sub_years  eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.sub_year_id    1   Using index
1   SIMPLE  vehicles_categories     eq_ref  PRIMARY     PRIMARY     4   tvs.vehicles.category_id    1   Using index

将此解释为一个答案:如果你还没有这些索引,你应该考虑添加它们

您是否也有这些方面的索引:

vehicles.status
vehicles.date_from
vehicles.date_to
vehicles.type_id
vehicles.price

比@Randy of indexes更具体一点,我相信他的意图是使用一个复合索引来利用您的查询临界值。。。一个建立在至少

( status, type_id, date_from )
但也可以扩展到包括日期和价格,但不知道该粒度级别的指数实际会有多大帮助

( status, type_id, date_from, date_to, price )
根据评论进行编辑

您不应该需要所有这些单独的索引。。。是的,主键本身。但是,对于其他查询条件,您应该基于您的通用查询条件使用复合索引,并删除其他查询条件。。。引擎可能会弄不清楚哪一个最适合查询。如果你知道你一直在寻找某个特定的状态、类型和日期(假设车辆搜索),将其作为一个索引。如果查询正在查找此类信息,但也在该条件内查找价格,那么它将非常接近于少数几个符合条件的索引记录,并将价格作为一个额外条件进行遍历

如果您只提供自动变速器和手动变速器之类的查询,而不考虑年份/品牌,那么是的,这可能是它自己的索引。但是,如果您通常有一些其他“通用”条件,请将其作为查询中可能使用的辅助条件。例如:如果您寻找2门和4门手动变速器,请打开索引(变速器id,类别id)


同样,您希望任何有助于缩小基于某些“最小”条件的标准范围的东西。如果您在索引上附加了一个可能“常用”的列,那么这只会有助于提高性能。

所有的行都使用一个边界框,只计算框内行的精确距离,而不是昂贵的精确距离计算

最简单的示例是计算您感兴趣的最小/最大经度和纬度,并将其添加到
WHERE
子句中。这样,将仅为行的子集计算距离

WHERE
    vehicles.gps_lat > min_lat ANDd vehicles.gps_lat < max_lat AND
    vehicles.gps_lon > min_lon AND vehicles.gps_lon < max_lon
在哪里
vehicles.gps\u lat>min\u lat和D vehicles.gps\u latmin_lon和vehicles.gps_lon
有关更复杂的解决方案,请参见:


    • 如果没有此功能,SQL是否会更快

      Round(3959 * Acos(Cos(Radians(51.465436)) *
        Cos(Radians(vehicles.gps_lat)) *
        Cos(Radians(vehicles.gps_lon) - 
        Radians(-0.296482)) + 
        Sin(Radians(51.465436)) * 
        Sin(Radians(vehicles.gps_lat)))) AS distance
      
      执行数学等式是非常昂贵的


      也许你应该考虑一个预先计算你的距离的物化视图,你可以从那个视图中选择。根据数据的动态程度,您可能不必经常刷新数据。

      改进WHERE子句

      您的解释表明,MySQL只使用一个索引(
      type\u id
      )来选择与
      WHERE
      子句匹配的行,即使该子句中有多个条件

      为了能够为WHERE子句中的所有标准使用索引,并尽快减小结果集的大小,请在vehicles表的以下列上添加多列索引:

      (status, date_from, date_to, type_id, price)
      
      列应按从最高基数到最低基数的顺序排列

      例如,
      vehicles.date\u from
      可能比
      status
      具有更多不同的值,因此将
      date\u from
      列置于
      status
      之前,如下所示:

      (date_from, date_to, price, type_id, status)
      
      这将减少查询执行的第一部分中返回的行数,并应在解释结果的第一行上显示较低的行数

      您还将注意到MySQL将使用多列索引作为解释结果中的WHERE。如果碰巧没有,您应该提示或强制使用多列索引

      删除不必要的连接

      您似乎没有在任何联接表中使用任何字段,因此请删除联接。这将删除查询的所有额外工作,并使您得到一个简单的执行计划(解释结果中的一行)


      每个联接表都会对结果集的每行进行额外的查找。因此,如果WHERE子句从车辆中选择5000行,因为您有8个到车辆的连接,那么您将有5000*8=40000个查找。您的数据库服务器有很多要求。

      我不熟悉复合索引-请参阅我的更新帖子。我当前的索引效率低吗?只需添加另一个索引,而不是一列,只需按照上面的操作,多列由列分隔。。。这样,一个索引可以有多个组件来更紧密地匹配查询条件。我有21个索引,我需要对它们进行分组,然后我需要先删除它们吗?+1这就是我想要的。。。似乎WHERE子句可能是罪魁祸首,对这些筛选列建立一个良好的索引会有很大帮助。@ChimeraTheory,对索引澄清的修订答案稍微有一点是的,但我需要在那里……如果我们要比较的字段来自联接表,索引有用吗?