如何减少mysql查询的运行时间

时间:2016-02-04 04:05:35

标签: mysql

这是我在网站的一个页面中运行的查询

SELECT 
    DISTINCT b.CruisePortID,
    b.SailingDates,
    b.CruisePortID,
    b.ArriveTime,
    b.DepartTime,
    b.PortName,
    b.DayNumber
FROM
    cruise_itineraries a,
    cruise_itinerary_days b,
    cruise_ports c
WHERE
a.ID = b.CruiseItineraryID
AND a.CruisePortID = c.ID
AND a.ID = '352905'
AND b.CruisePortID != 0
GROUP BY b.DayNumber;

在phpmy admin中运行此查询时,由于cruise_itineraries有超过300,000条记录,因此需要3.20秒 索引后我也尝试了索引,显示2.92秒。有可能减少查询时间减去.10秒。它帮助我的网站性能

此处详情

 CREATE TABLE IF NOT EXISTS `cruise_itineraries` (
  `cl` int(11) NOT NULL,
  `ID` bigint(20) NOT NULL,
  `Description` varchar(500) NOT NULL,
  `SailingPlanID` varchar(100) NOT NULL,
  `VendorID` varchar(100) NOT NULL,
  `VendorName` varchar(100) NOT NULL,
  `ShipID` varchar(100) NOT NULL,
  `ShipName` varchar(100) NOT NULL,
  `Duration` int(11) NOT NULL,
  `DestinationID` varchar(100) NOT NULL,
  `Date` datetime NOT NULL,
  `CruisePortID` varchar(100) NOT NULL,
  `TradeRestriction` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `cruise_itinerary_days` (
  `cld` int(11) NOT NULL,
  `CruiseItineraryID` varchar(100) NOT NULL,
  `SailingDates` datetime NOT NULL,
  `VendorID` int(11) NOT NULL,
  `VendorName` varchar(100) NOT NULL,
  `ShipID` int(11) NOT NULL,
  `ShipName` varchar(100) NOT NULL,
  `SailingPlanID` int(11) NOT NULL,
  `PlanName` varchar(100) NOT NULL,
  `DayNumber` bigint(20) NOT NULL,
  `PortName` varchar(100) NOT NULL,
  `CruisePortID` varchar(100) NOT NULL,
  `ArriveTime` varchar(100) NOT NULL,
  `DepartTime` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `cruise_ports` (
  `cp` int(11) NOT NULL,
  `ID` varchar(100) NOT NULL,
  `Name` varchar(100) NOT NULL,
  `Description` varchar(1000) NOT NULL,
  `NearestAirportCode` varchar(100) NOT NULL,
  `UNCode` varchar(100) NOT NULL,
  `Address` varchar(500) NOT NULL,
  `City` varchar(100) NOT NULL,
  `StateCode` varchar(100) NOT NULL,
  `CountryCode` varchar(100) NOT NULL,
  `PostalCode` varchar(100) NOT NULL,
  `Phone` varchar(50) NOT NULL,
  `Fax` varchar(100) NOT NULL,
  `Directions` varchar(1000) NOT NULL,
  `Content` varchar(1000) NOT NULL,
  `HomePageURL` varchar(100) NOT NULL,
  `Longitude` varchar(100) NOT NULL,
  `Latitude` varchar(500) NOT NULL,
  `CarnivalID` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;


    ALTER TABLE `cruise_itineraries`
  ADD PRIMARY KEY (`cl`),
  ADD KEY `ID_2` (`ID`);

    ALTER TABLE `cruise_itineraries`
  ADD PRIMARY KEY (`cl`),
  ADD KEY `ID_2` (`ID`);


ALTER TABLE `cruise_itinerary_days`
  ADD PRIMARY KEY (`cld`);

ALTER TABLE `cruise_ports`
  ADD PRIMARY KEY (`cp`);


ALTER TABLE `cruise_itineraries`
  MODIFY `cl` int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE `cruise_itinerary_days`
  MODIFY `cld` int(11) NOT NULL AUTO_INCREMENT;

ALTER TABLE `cruise_ports`
  MODIFY `cp` int(11) NOT NULL AUTO_INCREMENT;

分析结果:

+----+-------------+-------+------+---------------+------+---------+-------+---------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref   | rows    | Extra                                                  |
+----+-------------+-------+------+---------------+------+---------+-------+---------+--------------------------------------------------------+
|  1 | SIMPLE      | a     | ref  | ID_2          | ID_2 | 8       | const |       1 | Using index condition; Using temporary; Using filesort |
|  1 | SIMPLE      | c     | ALL  | NULL          | NULL | NULL    | NULL  |    3267 | Using where; Using join buffer (Block Nested Loop)     |
|  1 | SIMPLE      | b     | ALL  | NULL          | NULL | NULL    | NULL  | 2008191 | Using where; Using join buffer (Block Nested Loop)     |
+----+-------------+-------+------+---------------+------+---------+-------+---------+--------------------------------------------------------+

+----+-------------+-------+------+------------------------------------+------------------------------------+---------+-------+------+--------------------------------------------------------------+
| id | select_type | table | type | possible_keys                      | key                                | key_len | ref   | rows | Extra                                                        |
+----+-------------+-------+------+------------------------------------+------------------------------------+---------+-------+------+--------------------------------------------------------------+
|  1 | SIMPLE      | b     | ref  | Idx_CruiseItineraryID_CruisePortID | Idx_CruiseItineraryID_CruisePortID | 9       | const |   12 | Using index condition; Using temporary; Using filesort       |
|  1 | SIMPLE      | a     | ref  | ID_2                               | ID_2                               | 8       | const |    1 | Distinct                                                     |
|  1 | SIMPLE      | c     | ALL  | NULL                               | NULL                               | NULL    | NULL  | 3267 | Using where; Distinct; Using join buffer (Block Nested Loop) |
+----+-------------+-------+------+------------------------------------+------------------------------------+---------+-------+------+--------------------------------------------------------------+

1 个答案:

答案 0 :(得分:4)

首先,我想声明尽量避免 IMPLICIT MySQL JOINS 。 请改用 INNER JOINS

  

我个人认为INNER JOIN更好,因为它更多   可读。它表明了表格之间的关系。你得到了   在连接中的那些关系,并在WHERE中进行过滤   条款。这种分离使查询更具可读性。

我发现的错误:

  • cruise_itineraries.ID 的数据类型为 BIGINT cruise_itinerary_days.CruiseItineraryID 的数据类型为 varchar < / strong>即可。但是您在查询中匹配它们。因此,无论您是否在 cruise_itinerary_days 表格中使用cruise_itinerary_days.CruiseItineraryID 上的索引,它都将运行缓慢

    将cruise_itinerary_days.CruiseItineraryID的数据类型更改为BIGINT。

    ALTER TABLE cruise_itinerary_days MODIFY CruiseItineraryID BIGINT;

  • 接下来,您必须根据您的查询在cruise_itinerary_days表上创建一个复合索引。

    ALTER TABLE cruise_itinerary_days ADD INDEX Idx_CruiseItineraryID_CruisePortIDCruiseItineraryIDCruisePortID)`

  • 现在在cruise_ports.ID字段的cruise_ports表中创建一个索引。

    ALTER TABLE cruise_ports ADD INDEX Idx_cruise_ports_IDID);

最后查询是使用INNER JOINS制定的,因为我已经说明了上述理由背后的原因:

SELECT 
    DISTINCT b.CruisePortID,
    b.SailingDates,
    b.CruisePortID,
    b.ArriveTime,
    b.DepartTime,
    b.PortName,
    b.DayNumber
FROM cruise_itineraries a
INNER JOIN cruise_itinerary_days b ON a.ID = b.CruiseItineraryID
INNER JOIN cruise_ports c ON a.CruisePortID = c.ID
WHERE a.ID = 352905
AND b.CruisePortID != 0
GROUP BY b.DayNumber;