简体   繁体   English

如何使用JOIN加速复杂的SQL查询

[英]How to speed up a complex SQL query with JOINs

I am using the following query, and as you can see via the results below, it is taking 2+ hours to return the results. 我正在使用以下查询,正如您通过下面的结果所看到的,返回结果需要2个多小时。 I'd love to know how I could speed this up -- I believe I've already built the indexes correctly but it is still taking an incredible amount of time to return this data. 我很想知道如何加快速度 - 我相信我已经正确地构建了索引但是仍然需要花费大量的时间来返回这些数据。

EXPLAIN SELECT Import_Values.base_vehicle_id,
    Import_Values.qty,
    Import_Values.part_type_id,
    Import_Values.part_id,
    Import_Values.position_id,
    Import_Values.note,
    Parts.partterminologyname,
    BaseVehicle.YearID,
    Make.MakeName,
    Model.modelname,
    SubModel.SubModelName,
    EngineDesignation.EngineDesignationName,
    EngineVIN.EngineVINName,
    EngineBase.Liter,
    EngineBase.CC,
    EngineBase.CID,
    EngineBase.Cylinders,
    EngineBase.BlockType,
    EngineBase.EngBoreIn,
    EngineBase.EngBoreMetric,
    EngineBase.EngStrokeIn,
    EngineBase.EngStrokeMetric,
    FuelDeliveryType.FuelDeliveryTypeName,
    FuelDeliverySubType.FuelDeliverySubTypeName,
    FuelSystemControlType.FuelSystemControlTypeName,
    FuelSystemDesign.FuelSystemDesignName,
    Aspiration.AspirationName,
    CylinderHeadType.CylinderHeadTypeName,
    FuelType.FuelTypeName,
    IgnitionSystemType.IgnitionSystemTypeName,
    Mfr.MfrName,
    EngineVersion.EngineVersion,
    Valves.ValvesPerEngine,
    BedLength.BedLength,
    BedLength.BedLengthMetric,
    BedType.BedTypeName
    FROM 
    Import_Values
    INNER JOIN BaseVehicle 
        ON Import_Values.base_vehicle_id=BaseVehicle.BaseVehicleID
    INNER JOIN Parts 
        ON Import_Values.part_type_id=Parts.PartTerminologyID
    INNER JOIN Make
        ON BaseVehicle.MakeID=Make.MakeID
    INNER JOIN Model
        ON BaseVehicle.ModelID=Model.ModelID
    INNER JOIN Vehicle
        ON Import_Values.base_vehicle_id=Vehicle.BaseVehicleID
    INNER JOIN SubModel
        ON Vehicle.SubModelID=SubModel.SubModelID
    INNER JOIN VehicleConfig
        ON Vehicle.VehicleID=VehicleConfig.VehicleID
    INNER JOIN EngineConfig
        ON VehicleConfig.EngineConfigID=EngineConfig.EngineConfigID
    INNER JOIN EngineDesignation
        ON EngineConfig.EngineDesignationID=EngineDesignation.EngineDesignationID
    INNER JOIN EngineVIN
        ON EngineConfig.EngineVINID=EngineVIN.EngineVINID
    INNER JOIN EngineBase
        ON EngineConfig.EngineBaseID=EngineBase.EngineBaseID
    INNER JOIN FuelDeliveryConfig
        ON EngineConfig.FuelDeliveryConfigID=FuelDeliveryConfig.FuelDeliveryConfigID
    INNER JOIN FuelDeliveryType
        ON FuelDeliveryConfig.FuelDeliveryTypeID=FuelDeliveryType.FuelDeliveryTypeID
    INNER JOIN FuelDeliverySubType
        ON FuelDeliveryConfig.FuelDeliverySubTypeID=FuelDeliverySubType.FuelDeliverySubTypeID
    INNER JOIN FuelSystemControlType
        ON FuelDeliveryConfig.FuelSystemControlTypeID=FuelSystemControlType.FuelSystemControlTypeID
    INNER JOIN FuelSystemDesign
        ON FuelDeliveryConfig.FuelSystemDesignID=FuelSystemDesign.FuelSystemDesignID
    INNER JOIN Aspiration
        ON EngineConfig.AspirationID=Aspiration.AspirationID
    INNER JOIN CylinderHeadType
        ON EngineConfig.CylinderHeadTypeID=CylinderHeadType.CylinderHeadTypeID
    INNER JOIN FuelType
        ON EngineConfig.FuelTypeID=FuelType.FuelTypeID
    INNER JOIN IgnitionSystemType
        ON EngineConfig.IgnitionSystemTypeID=IgnitionSystemType.IgnitionSystemTypeID
    INNER JOIN Mfr
        ON EngineConfig.EngineMfrID=Mfr.MfrID
    INNER JOIN EngineVersion
        ON EngineConfig.EngineVersionID=EngineVersion.EngineVersionID
    INNER JOIN Valves
        ON EngineConfig.ValvesID=Valves.Valvesid
    INNER JOIN BedConfig
        ON VehicleConfig.BedConfigID=BedConfig.BedConfigID
    INNER JOIN BedLength
        ON BedConfig.BedLengthID=BedLength.BedLengthID
    INNER JOIN BedType
        ON BedConfig.BedTypeID=BedType.BedTypeID

And the results... 结果......

+----+-------------+-----------------------+--------+-----------------------+---------+---------+-----------------------------------------------------------------+--------+-------------------+
| id | select_type | table                 | type   | possible_keys         | key     | key_len | ref                                                             | rows   | Extra             |
+----+-------------+-----------------------+--------+-----------------------+---------+---------+-----------------------------------------------------------------+--------+-------------------+
|  1 | SIMPLE      | VehicleConfig         | ALL    | NULL                  | NULL    | NULL    | NULL                                                            | 171375 |                   |
|  1 | SIMPLE      | Import_Values         | ALL    | base_vehicle_id       | NULL    | NULL    | NULL                                                            |  18933 | Using join buffer |
|  1 | SIMPLE      | BedConfig             | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.VehicleConfig.BedConfigID                  |      1 |                   |
|  1 | SIMPLE      | BedType               | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.BedConfig.BedTypeID                        |      1 |                   |
|  1 | SIMPLE      | BedLength             | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.BedConfig.BedLengthID                      |      1 |                   |
|  1 | SIMPLE      | EngineConfig          | eq_ref | PRIMARY,EngineBaseID  | PRIMARY | 4       | icarcare_importfeeds.VehicleConfig.EngineConfigID               |      1 |                   |
|  1 | SIMPLE      | FuelType              | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.FuelTypeID                    |      1 |                   |
|  1 | SIMPLE      | Valves                | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.ValvesID                      |      1 |                   |
|  1 | SIMPLE      | EngineVIN             | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.EngineVINID                   |      1 |                   |
|  1 | SIMPLE      | EngineVersion         | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.EngineVersionID               |      1 |                   |
|  1 | SIMPLE      | IgnitionSystemType    | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.IgnitionSystemTypeID          |      1 |                   |
|  1 | SIMPLE      | Mfr                   | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.EngineMfrID                   |      1 |                   |
|  1 | SIMPLE      | Aspiration            | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.AspirationID                  |      1 |                   |
|  1 | SIMPLE      | FuelDeliveryConfig    | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.FuelDeliveryConfigID          |      1 |                   |
|  1 | SIMPLE      | FuelSystemDesign      | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.FuelDeliveryConfig.FuelSystemDesignID      |      1 |                   |
|  1 | SIMPLE      | FuelDeliverySubType   | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.FuelDeliveryConfig.FuelDeliverySubTypeID   |      1 |                   |
|  1 | SIMPLE      | EngineDesignation     | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.EngineDesignationID           |      1 |                   |
|  1 | SIMPLE      | EngineBase            | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.EngineBaseID                  |      1 |                   |
|  1 | SIMPLE      | CylinderHeadType      | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.EngineConfig.CylinderHeadTypeID            |      1 |                   |
|  1 | SIMPLE      | Parts                 | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.Import_Values.part_type_id                 |      1 | Using where       |
|  1 | SIMPLE      | FuelSystemControlType | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.FuelDeliveryConfig.FuelSystemControlTypeID |      1 |                   |
|  1 | SIMPLE      | BaseVehicle           | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.Import_Values.base_vehicle_id              |      1 | Using where       |
|  1 | SIMPLE      | Make                  | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.BaseVehicle.MakeID                         |      1 |                   |
|  1 | SIMPLE      | Model                 | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.BaseVehicle.ModelID                        |      1 |                   |
|  1 | SIMPLE      | Vehicle               | eq_ref | PRIMARY,BaseVehicleID | PRIMARY | 4       | icarcare_importfeeds.VehicleConfig.VehicleID                    |      1 | Using where       |
|  1 | SIMPLE      | SubModel              | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.Vehicle.SubModelID                         |      1 |                   |
|  1 | SIMPLE      | FuelDeliveryType      | eq_ref | PRIMARY               | PRIMARY | 4       | icarcare_importfeeds.FuelDeliveryConfig.FuelDeliveryTypeID      |      1 |                   |
+----+-------------+-----------------------+--------+-----------------------+---------+---------+-----------------------------------------------------------------+--------+-------------------+
27 rows in set (2 hours 39 min 30.51 sec)

Is there anything I can do? 有什么我能做的吗? I've tried analyzing the tables, optimizing them, etc. It just seems there must be more to do than let it run for 2 hours, lol. 我试过分析表格,优化它们等等。似乎必须要做的事情要比让它运行2小时更多,哈哈。

Are you sure that your query is logically correct? 您确定您的查询在逻辑上是正确的吗? I know nothing about your database so I can't tell what's going on, but here is a tiny bit of the query that seems to go against the pattern set down by the rest of the lookups in the query. 我对你的数据库一无所知,所以我不知道发生了什么,但这里有一小部分查询似乎违反了查询中其余查找设置的模式。

Here it is: 这里是:

INNER JOIN Vehicle
    ON Import_Values.base_vehicle_id=Vehicle.BaseVehicleID

This looks strange, given the rest of your query. 鉴于您的其余查询,这看起来很奇怪。 I would have expected the ON condition to be looking up one entry in Vehicle based on Vehicle.VehicleID which is probably the indexed field in that table. 我本来期望ON条件是基于Vehicle.VehicleID在Vehicle中查找一个条目,这可能是该表中的索引字段。 Instead, it's looking it up based on Vehicle.BaseVehicleID which is probably an unindexed field. 相反,它正在根据Vehicle.BaseVehicleID查找它,这可能是一个未编入索引的字段。

It's entirely possible that this is logically correct. 完全有可能这在逻辑上是正确的。 But if it's logically incorrect, it could explain the long delay. 但如果它在逻辑上不正确,它可以解释长时间的延迟。 If this turns out to be the case, then your query will deliver wrong results in addition to taking too long to complete. 如果情况确实如此,那么除了花费太长时间完成之外,您的查询将提供错误的结果。

Edit: 编辑:

What is the relationship between ImportValues, Vehicle, and VehicleConfig? ImportValues,Vehicle和VehicleConfig之间有什么关系? Are there many VehicleConfigs for one Vehicle? 一辆车有很多VehicleConfigs吗? Or is it vice versa? 或反之亦然?

It looks like The explain plan ended up using a plan that amounts to a Cartesian Join between ImportValues and VehicleConfig. 看起来解释计划最终使用的计划相当于ImportValues和VehicleConfig之间的笛卡尔连接。 It's very unusual for a Cartesian join to produce the desired results. 笛卡尔联合产生预期结果是非常不寻常的。 In any event, you can expect a Cartesian Join to take a long, long time. 无论如何,你可以期待笛卡尔式加入需要很长时间。 Even if the query doesn't yield a Cartesian join, if the plan uses the same algorithm, it's still going to take a long, long time. 即使查询没有产生笛卡尔连接,如果计划使用相同的算法,它仍然需要很长很长时间。

Second Edit: 第二编辑:

There is another join condition that looks anomalous. 还有另一个看似异常的连接条件。 It's the join condition under VehicleConfig. 这是VehicleConfig下的连接条件。

INNER JOIN VehicleConfig
        ON Vehicle.VehicleID=VehicleConfig.VehicleID

This is a pretty good join condition, but not for the VehicleConfig table. 这是一个非常好的连接条件,但不适用于VehicleConfig表。 What it says, in plain English, is that VehicleConfig determines Vehicle. 用简单的英语说,它说的是VehicleConfig确定车辆。 Not terribly surprising given the names of the tables and columns. 考虑到表格和列的名称,这并不奇怪。

But what determines VehicleConfig? 但是什么决定了VehicleConfig?

If the answer is "nothing", then it's no wonder that poor old MySQL is doing a full scan on the table, in addition to a full scan on Import_Values. 如果答案是“什么都没有”,那么除了在Import_Values上进行全面扫描之外,糟糕的旧MySQL正在对表进行全面扫描也就不足为奇了。

My conclusion: fix your query so that 26 of the 27 tables are determined by an FK that references the table's PK. 我的结论是:修复你的查询,以便27个表中的26个由引用表的PK的FK确定。 24 of your joins already meet this criterion. 您的24个联接已经符合此标准。 When you are finally done, and you do an explain plan, you should see only one table doing a full table scan, namely the Import_Values table. 当您最终完成并执行解释计划时,您应该只看到一个表执行全表扫描,即Import_Values表。

It should run faster, and it's more likely to produce correct results. 它应该运行得更快,并且更有可能产生正确的结果。

In looking at your explain plan, it looks like it's fine for everything except for Import_Values and VehicleConfig. 在查看您的解释计划时,除了Import_Values和VehicleConfig之外,它看起来很好。 It doesn't even look like it is considering any keys for VehicleConfig and just going straight into a full table scan which is bad. 它甚至看起来都没有考虑到VehicleConfig的任何键,只是直接进入全表扫描,这是不好的。

Try creating a composite index for VehicleConfig on VehicleID and BedConfigID and an index for Import_Values on base_vehicle_id and part_type_id. 尝试在VehicleID和BedConfigID上为VehicleConfig创建复合索引,在base_vehicle_id和part_type_id上​​为Import_Values创建索引。 If they already have indexes, it may just be a matter of updating statistics which you can do with the following commands. 如果它们已经有索引,则可能只需要更新可以使用以下命令执行的统计信息。 Hope that helps. 希望有所帮助。

ANALYZE TABLE VehicleConfig
ANALYZE TABLE Import_Values

请在执行此查询时尝试应用执行计划,并查看是否未建议任何缺少的键/索引。

Try to set forceplan on and run the query. 尝试设置forceplan并运行查询。 Another suggesstion is to break the query into multiple queries with 6-7 table joins in each query. 另一个建议是将查询分解为多个查询,每个查询中有6-7个表连接。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM