MySQL - 具有一个变量更改的 SAME 查询花费的时间超过 10 倍

标签 mysql caching optimization

我有 MySQL 数据库,我总是问同样的“问题”,我唯一改变的是查询中的 VIN 变量。

更具体地说,我向您展示了 2 个查询: 第一个带有 VIN 的:U5YFF24128L064909(耗时 0.0002 秒)

SELECT  c.vin, c.case_id, c.claimnumber, c.platenumber, c.axrmrs_id,
        c.insurer_memberid, c.country, c.date_created, c.totalloss,
        c.lastcalc_manufacturer_code, c.lastcalc_model_code, c.lastcalc_submodel_code,
        c.audavin_triggered, c.accident_date, c.registration_date,
        c.manufacturing_year, cl.spareparts, cl.totalcosts, cl.laborhours,
        cl.laborcosts, cl.calculationdate, cl.paintlabor, cl.paintmaterial,
        cl.currency, car.manufacturer, car.model, car.submodel,
        IFNULL(org.name, 0) as orgName, GROUP_CONCAT(DISTINCT IF(po.repairmethod LIKE 'L%',
                       po.text,NULL)
            ORDER BY  1) AS textL, GROUP_CONCAT(DISTINCT IF(po.repairmethod = 'E',
                       po.text,NULL
                          )
            ORDER BY  1) AS textE , GROUP_CONCAT(DISTINCT IF(po.repairmethod != 'E'
                      OR  (po.repairmethod = 'E'
                              AND  po.guidenumber = 'N/A'
                          )
                      AND  po.repairmethod NOT LIKE 'L%',po.text, NULL
                          )
            ORDER BY  1
              ) AS textO
    FROM  axnmrs_cases AS c
    LEFT JOIN  axnmrs_calculations as cl on c.case_id = cl.case_id
      AND  c.country = cl.country
    LEFT JOIN  axnmrs_positions as po on c.case_id = po.case_id
    LEFT JOIN  car_type as car on car.manufacturer_code = c.lastcalc_manufacturer_code
      AND  car.main_type = c.lastcalc_model_code
      AND  car.subtype_code = c.lastcalc_submodel_code
    LEFT JOIN  organization_list as org on org.memberId = c.insurer_memberid
    WHERE  c.vin= 'U5YFF24128L064909'
    GROUP BY  c.vin, c.case_id, c.axrmrs_id 

第二个 VIN = VF38BRHZE80728805(这需要 2.4387 秒)

SELECT  c.vin, c.case_id, c.claimnumber, c.platenumber, c.axrmrs_id,
        c.insurer_memberid, c.country, c.date_created, c.totalloss,
        c.lastcalc_manufacturer_code, c.lastcalc_model_code, c.lastcalc_submodel_code,
        c.audavin_triggered, c.accident_date, c.registration_date,
        c.manufacturing_year, cl.spareparts, cl.totalcosts, cl.laborhours,
        cl.laborcosts, cl.calculationdate, cl.paintlabor, cl.paintmaterial,
        cl.currency, car.manufacturer, car.model, car.submodel,
        IFNULL(org.name, 0) as orgName, GROUP_CONCAT(DISTINCT IF(po.repairmethod LIKE 'L%',
                       po.text,NULL)
            ORDER BY  1) AS textL, GROUP_CONCAT(DISTINCT IF(po.repairmethod = 'E',
                       po.text,NULL
                          )
            ORDER BY  1) AS textE , GROUP_CONCAT(DISTINCT IF(po.repairmethod != 'E'
                      OR  (po.repairmethod = 'E'
                              AND  po.guidenumber = 'N/A'
                          )
                      AND  po.repairmethod NOT LIKE 'L%',po.text, NULL
                          )
            ORDER BY  1
              ) AS textO
    FROM  axnmrs_cases AS c
    LEFT JOIN  axnmrs_calculations as cl on c.case_id = cl.case_id
      AND  c.country = cl.country
    LEFT JOIN  axnmrs_positions as po on c.case_id = po.case_id
    LEFT JOIN  car_type as car on car.manufacturer_code = c.lastcalc_manufacturer_code
      AND  car.main_type = c.lastcalc_model_code
      AND  car.subtype_code = c.lastcalc_submodel_code
    LEFT JOIN  organization_list as org on org.memberId = c.insurer_memberid
    WHERE  c.vin= 'VF38BRHZE80728805'
    GROUP BY  c.vin, c.case_id, c.axrmrs_id 

我不知道为什么会这样,所以我尝试分析,所以我在 PHPMYADMIN 中使用“PROFILE”函数,它在屏幕上返回如下结果: 车牌号:U5YFF24128L064909 enter image description here

和 VIN:VF38BRHZE80728805(显然是更长的操作) enter image description here

因为我无法从中搜索到任何有用的信息,所以我也尝试了如下所示的 EXPLAIN SELECT 查询: 对于 VIN:U5YFF24128L064909 enter image description here

对于 VIN:VF38BRHZE80728805 enter image description here

根据这个解释,我认为我在 car_type 表上做的查询不好,应该写得更好,但是它不会改变相同查询的速度,只是使用不同的 VIN 号码。

我还认为我的第一个 QUERY 只是从 CACHE 返回,第二个来自 DB。所以我尝试再次进行这两个查询。并且两者再次花费与以前相同的时间。

有没有人可以帮我找出这个查询的问题所在?我做错了什么?

感谢您的任何建议,因为我已经迷失在其中了!

编辑: 在 car_type 表中,我有以下索引:manufacturer_codemain_typesubtype_code

编辑2: 为了更深入地分析,我尝试 SHOW CREATE TABLE {{table name}} 结果如下。

axnmrs_cases:

CREATE TABLE `axnmrs_cases` (
    `axrmrs_id` int(11) NOT NULL DEFAULT '0', 
    `case_id` int(11) NOT NULL DEFAULT '0', 
    `axncase_guid` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `date_created` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `datasource` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `claimnumber` varchar(60) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `platenumber` varchar(60) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `displayname` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `vin` varchar(40) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `lastcalc_manufacturer_code` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `lastcalc_model_code` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `lastcalc_submodel_code` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `lastcalc_model_options` varchar(500) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `audavin_triggered` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `vehicletype` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `accident_date` timestamp NULL DEFAULT '0000-00-00 00:00:00', 
    `date_closed` timestamp NULL DEFAULT '0000-00-00 00:00:00', 
    `claimowner_memberid` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `repairer_memberid` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `insurer_memberid` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `assessor_memberid` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `accidentcause_code` int(11) DEFAULT NULL, 
    `casetype_code` int(11) DEFAULT NULL, 
    `claimtype_code` int(11) DEFAULT NULL, 
    `damagecause_code` int(11) DEFAULT NULL, 
    `damagearea_codes` varchar(20) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `totalloss` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `inspectionrequired` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `manufacturing_year` int(11) NOT NULL DEFAULT '0', 
    `registration_date` timestamp NULL DEFAULT '0000-00-00 00:00:00', 
    `mileage` int(11) NOT NULL DEFAULT '0', 
    `country` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    PRIMARY KEY (`id`), 
    KEY `VIN_index` (`vin`)
) ENGINE=InnoDB AUTO_INCREMENT=3471525 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

axnmrs_calculations:

CREATE TABLE `axnmrs_calculations` (
    `calculation_id` int(11) NOT NULL, 
    `case_id` int(11) NOT NULL, 
    `guid` varchar(50) NOT NULL, 
    `calculationdate` varchar(50) NOT NULL, 
    `name` varchar(50) NOT NULL, 
    `calsscalnr` varchar(50) NOT NULL, 
    `model_options` varchar(60) NOT NULL, 
    `spareparts` varchar(60) NOT NULL, 
    `laborcosts` varchar(60) NOT NULL, 
    `paintlabor` varchar(60) NOT NULL, 
    `paintmaterial` varchar(40) NOT NULL, 
    `extracosts` varchar(60) NOT NULL, 
    `environmentalcosts` varchar(60) NOT NULL, 
    `totalcosts` varchar(60) NOT NULL, 
    `totalvat` varchar(60) NOT NULL, 
    `laborhours` varchar(60) NOT NULL, 
    `painthours` varchar(60) NOT NULL, 
    `totaldeduction` varchar(60) NOT NULL, 
    `partsadjustment` varchar(60) NOT NULL, 
    `calculationtype` varchar(60) NOT NULL, 
    `license` varchar(60) NOT NULL, 
    `memberrole` varchar(60) NOT NULL, 
    `currency` varchar(5) NOT NULL, 
    `country` varchar(2) NOT NULL, 
    KEY `caseid_index` (`case_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

axnmrs_positions:

CREATE TABLE `axnmrs_positions` (
    `calculation_id` int(11) NOT NULL DEFAULT '0', 
    `case_id` int(11) NOT NULL DEFAULT '0', 
    `position_id` int(11) NOT NULL DEFAULT '0', 
    `blockline` varchar(7) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `repairmethod` varchar(3) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `guidenumber` varchar(4) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `amount` float NOT NULL DEFAULT '0', 
    `hours` float NOT NULL DEFAULT '0', 
    `starmutation` varchar(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `text` varchar(200) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `originalpartnumber` varchar(50) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `originalpartprice` float NOT NULL DEFAULT '0', 
    `manufacturercode` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `quality` varchar(5) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    `suppliercode` varchar(10) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0', 
    KEY `calculationid_index` (`calculation_id`), 
    KEY `repairmethod` (`repairmethod`), 
    KEY `caseid_index` (`case_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci

汽车类型:

CREATE TABLE `car_type` (
    `manufacturer_code` varchar(2) NOT NULL, 
    `main_type` varchar(2) NOT NULL, 
    `subtype_code` varchar(2) NOT NULL, 
    `manufacturer` varchar(100) NOT NULL, 
    `model` varchar(20) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL, 
    `submodel` varchar(20) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL, 
    KEY `manufacturer_code` (`manufacturer_code`), 
    KEY `main_type` (`main_type`), 
    KEY `subtype_code` (`subtype_code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

组织列表:

CREATE TABLE `organization_list` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `memberId` varchar(99) NOT NULL, 
    `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_czech_ci NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `memberId` (`memberId`)
) ENGINE=InnoDB AUTO_INCREMENT=133 DEFAULT CHARSET=latin1

最佳答案

配置文件为您提供了答案——查询缓存

从 0.2 中的查询中获取结果的唯一方法是它来自“查询缓存”。这是对结果集的选择的散列。您显然运行了两次查询,这是第二次。使用 SELECT SQL_NO_CACHE ... 再试一次,看看它“真正”需要多长时间。

请注意,“查询缓存”并不是 MySQL 使用的唯一“缓存”;所以在使用术语时要小心。

(这不是 10 倍;那是 10000 倍长。)

除此之外,您的下一个问题是为什么这样的查询需要 2.4 秒?这是您应该解决的问题。线索在 EXPLAIN 中——首先请注意 car 的巨大“行”。

    LEFT JOIN car_type as car
      on car.manufacturer_code = c.lastcalc_manufacturer_code
     AND car.main_type = c.lastcalc_model_code
     AND car.subtype_code = c.lastcalc_submodel_code

将此复合索引添加到 car_type 将加快该部分查询的速度。

INDEX(manufacturer_code, main_type, subtype_code)

(在这种情况下顺序无关紧要。)

另外,

    LEFT JOIN organization_list as org on org.memberId = c.insurer_memberid

需要一致的 memberId 定义。仔细查看两个表中的CHARACTER SET

使用 ALTER TABLE ... CONVERT TO ... 解决此问题,以便它可以使用索引。

另见 Index Cookbook

关于MySQL - 具有一个变量更改的 SAME 查询花费的时间超过 10 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34679256/

相关文章:

spring-boot - 在 Aerospike 中更新单个字段的最佳方法

java - 基于Spring boot的REST服务,带有hazelcast的spring缓存无法处理缓存错误

optimization - 在序言中找到可能的最高评价

mysql - JPQL只返回第一条记录

php - 使用终端在MySQL中创建的数据库与PhpMyAdmin中显示的数据库是否不同?

caching - Redis作为服务启动【无法识别的服务错误】

java - 正则表达式的优化

php - 推荐用户资料功能需要表代码设计

mysql - 从 mySQL 中检索至少一定数量的记录

algorithm - 最小化到加权网格的距离