优化 mysql 查询以获得更好的性能以缩短执行时间

Optimizing mysql query for better performance to get low execution time

目前我的 php 代码中有这个 mysql 查询。我想更好地优化它,因为这个查询当前在一个 while 循环中,而且这个查询本身就需要 25 秒。所以循环越大,一遍又一遍地执行这个查询所花费的时间就会在很短的时间内变得疯狂。所以我很想就此获得一些帮助。

$select_count = "select site_id, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Nozzle = 1) IS_Nozzle, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Electronic_Components = 1) IS_Electronic_Components, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Power_device = 1) IS_Power_device, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Consumable = 1) IS_Consumable, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Hose = 1) IS_Hose, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Switch = 1) IS_Switch, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Valve = 1) IS_Valve, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Housing_Frame = 1) IS_Housing_Frame, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Pump = 1) IS_Pump, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Totalizer = 1) IS_Totalizer, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Flow_Meter = 1) IS_Flow_Meter, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Swivel = 1) IS_Swivel, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Submersible = 1) IS_Submersible, "
                . "(select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '$from' AND '$to') AND "
                . "Site_ID = $site_id and IS_Other = 1) IS_Other "
                . "FROM Site_detail x "
                . "WHERE is_maintenance = 1";

编辑

这是 sql 查询

select site_id
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Nozzle = 1) IS_Nozzle
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Electronic_Components = 1) IS_Electronic_Components
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Power_device = 1) IS_Power_device
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Consumable = 1) IS_Consumable
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Hose = 1) IS_Hose
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Switch = 1) IS_Switch
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Valve = 1) IS_Valve
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Housing_Frame = 1) IS_Housing_Frame
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Pump = 1) IS_Pump
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Totalizer = 1) IS_Totalizer
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Flow_Meter = 1) IS_Flow_Meter
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Swivel = 1) IS_Swivel
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Submersible = 1) IS_Submersible
     , (select count(id) from Tbl_WO_Detail WHERE Description != 'PM' AND (WO_Date between '2020-12-1' AND '2020-12-2') AND Site_ID = 1342 and IS_Other = 1) IS_Other 
  FROM Site_detail x 
 WHERE is_maintenance = 1

还有 对于 table site_details

CREATE TABLE `site_detail` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `site_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `site_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `owner_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
 `owner_phone` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
 `commission_date` date DEFAULT NULL,
 `noofpressure_unit` bigint(20) DEFAULT NULL,
 `noofsuction_unit` bigint(20) DEFAULT NULL,
 `region_id` bigint(20) DEFAULT NULL,
 `oilcompany_id` bigint(20) DEFAULT NULL,
 `subregion_id` bigint(20) DEFAULT NULL,
 `natures` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `is_maintenance` tinyint(4) DEFAULT NULL,
 `site_no` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Asset_Qty` bigint(20) unsigned DEFAULT NULL,
 `TimeStamp` datetime DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=46712 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC

CREATE TABLE `tbl_wo_detail` (
 `id` int(11) NOT NULL AUTO_INCREMENT,
 `WO_No` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Caller_No` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Contact_Person` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `WO_Date` date DEFAULT NULL,
 `WO_Time` time DEFAULT NULL,
 `OC_Date` date DEFAULT NULL,
 `OC_Time` time DEFAULT NULL,
 `OC_ID` int(11) DEFAULT NULL,
 `Complain_No` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Description` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Site_ID` int(11) DEFAULT NULL,
 `Subregion` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Target_Date` date DEFAULT NULL,
 `Target_Time` time DEFAULT NULL,
 `WO_Priority` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `WO_Status` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Down_Time` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Remarks` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Task_Mode` varchar(50) COLLATE utf8_unicode_ci DEFAULT 'Open',
 `Detail_Other` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Solution` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Finish_Date` date DEFAULT NULL,
 `Finish_T1` time DEFAULT NULL,
 `Finish_T2` time DEFAULT NULL,
 `Pay_Mode` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `PO_Number` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Customer_Name` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Customer_Comments` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `Prd_Qty` int(11) DEFAULT NULL,
 `Tech_Qty` int(11) DEFAULT NULL,
 `MRRNo` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
 `IS_Nozzle` tinyint(4) DEFAULT 0,
 `IS_Electronic_Components` tinyint(4) DEFAULT 0,
 `IS_Power_device` tinyint(4) DEFAULT 0,
 `IS_Consumable` tinyint(4) DEFAULT 0,
 `IS_Hose` tinyint(4) DEFAULT 0,
 `IS_Switch` tinyint(4) DEFAULT 0,
 `IS_Valve` tinyint(4) DEFAULT 0,
 `IS_Housing_Frame` tinyint(4) DEFAULT 0,
 `IS_Pump` tinyint(4) DEFAULT 0,
 `IS_Totalizer` tinyint(4) DEFAULT 0,
 `IS_Flow_Meter` tinyint(4) DEFAULT 0,
 `IS_Swivel` tinyint(4) DEFAULT 0,
 `IS_Preventive_Maintenance` tinyint(4) DEFAULT 0,
 `IS_Submersible` tinyint(4) DEFAULT 0,
 `IS_Other` tinyint(4) DEFAULT 0,
 `Edit_DateTime` datetime DEFAULT NULL,
 `chkVIS` tinyint(4) DEFAULT 0,
 PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=444908 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ROW_FORMAT=DYNAMIC

看起来像

SELECT site_id, 
       SUM(IS_Nozzle = 1) IS_Nozzle, 
       SUM(IS_Electronic_Components = 1) IS_Electronic_Components, 
       SUM(IS_Power_device = 1) IS_Power_device, 
       SUM(IS_Consumable = 1) IS_Consumable, 
       SUM(IS_Hose = 1) IS_Hose, 
       SUM(IS_Switch = 1) IS_Switch, 
       SUM(IS_Valve = 1) IS_Valve, 
       SUM(IS_Housing_Frame = 1) IS_Housing_Frame, 
       SUM(IS_Pump = 1) IS_Pump, 
       SUM(IS_Totalizer = 1) IS_Totalizer, 
       SUM(IS_Flow_Meter = 1) IS_Flow_Meter, 
       SUM(IS_Swivel = 1) IS_Swivel, 
       SUM(IS_Submersible = 1) IS_Submersible, 
       SUM(IS_Other = 1) IS_Other 
FROM Site_detail x 
JOIN Tbl_WO_Detail y USING (site_id)
WHERE x.is_maintenance = 1
  AND y.Description != 'PM' 
  AND y.WO_Date between '$from' AND '$to'
GROUP BY site_id;

如果条件(IS_Nozzle、IS_Electronic_Components 等)中使用的列是布尔列(仅包含 0 或 1),则可以删除 = 1

PS。在最后一种情况下,我建议使用 SET 数据类型的一列而不是许多单独的列。

我会推荐 Akina 方法的一种变体:

SELECT sd.site_id, wd.IS_Nozzle, wd.IS_Electronic_Components,  wd.IS_Power_device,  wd.IS_Consumable, 
       wd.IS_Hose wd.IS_Switch, wd.IS_Valve, wd.IS_Housing_Frame, wd.IS_Pump, wd.IS_Totalizer, 
       wd.IS_Flow_Meter, wd.IS_Swivel, wd.IS_Submersible, wd.IS_Other 
FROM Site_detail sd JOIN
     (SELECT SUM(IS_Nozzle = 1) as IS_Nozzle, 
             SUM(IS_Electronic_Components = 1) as IS_Electronic_Components, 
             SUM(IS_Power_device = 1) as IS_Power_device, 
             SUM(IS_Consumable = 1) as IS_Consumable, 
             SUM(IS_Hose = 1) as IS_Hose, 
             SUM(IS_Switch = 1) as IS_Switch, 
             SUM(IS_Valve = 1) as IS_Valve, 
             SUM(IS_Housing_Frame = 1) as IS_Housing_Frame, 
             SUM(IS_Pump = 1) as IS_Pump, 
             SUM(IS_Totalizer = 1) as IS_Totalizer, 
             SUM(IS_Flow_Meter = 1) as IS_Flow_Meter, 
             SUM(IS_Swivel = 1) as IS_Swivel, 
             SUM(IS_Submersible = 1) as IS_Submersible, 
             SUM(IS_Other = 1) as IS_Other
      FROM Tbl_WO_Detail wd
      WHERE wd.Description <> 'PM' AND
            wd.WO_Date BETWEEN ? AND ?
      GROUP BY wd.site_id
     ) wd
      USING (site_id)
WHERE sd.is_maintenance = 1
GROUP BY sd.site_id;

然后可以在 Site_detail(id_maintenance, site_id)Tbl_WO_Detail(WO_Date, Description) 上使用索引。

请注意在此查询中使用 有意义的 table 别名而不是任意字母,例如 xy.

最重要的是:将参数值作为 参数 传递。 不要混淆带有参数值的查询字符串!

四件事要解决;很难说哪个对性能最有帮助:

Pivot: 关于如何有效地进行旋转,有两个很好的答案。更多...

site_id: 一个主要问题:site_id 在两个细节中具有不同的数据类型(VARCHAR 与 INT)。这导致 JOIN 的性能很差。修理它!当你这样做的时候,考虑 site_id 是否应该是 site_detailPRIMARY KEY

引擎:使用InnoDB,不使用MyISAM。

索引:

site_detail:  (is_maintenance, site_id)
wo_detail:    (date, site_id)
wo_detail:    (site_id, date)