简体   繁体   English

或在MySQL中使查询非常慢

[英]OR in MySQL where makes query very slow

I have a big query in MySQL for magento which takes way to much time. 我在MySQL中有一个关于magento的大查询,这需要很多时间。 I tried to optimize it but my MySQL knowledge isn't enough to get it solved, so maybe someone could take a look and give me some hints in the right direction. 我试图对其进行优化,但是我的MySQL知识不足以解决它,因此也许有人可以看看并向我提供一些正确方向的提示。

Select Distinct
  `e`.*,
  `cat_index`.`position` AS `cat_index_position`,
  `price_index`.`price`,
  `price_index`.`tax_class_id`,
  `price_index`.`final_price`,
  IF(price_index.tier_price IS NOT NULL, 
      LEAST(price_index.min_price, price_index.tier_price),
      price_index.min_price) AS `minimal_price`,
  `price_index`.`min_price`,
  `price_index`.`max_price`,
  `price_index`.`tier_price`
From
  `catalog_product_entity` AS `e`
    Inner Join
  `catalog_category_product_index` As `cat_index`
    On cat_index.product_id=e.entity_id And
       cat_index.store_id=1 And
       cat_index.visibility In(2, 4) And
       cat_index.category_id='2'
    Inner Join
  `catalog_product_index_price` AS `price_index` 
    On price_index.entity_id = e.entity_id And
       price_index.website_id = '1' And
       price_index.customer_group_id = 0
    Left Join
  `beta_entity_product` AS `beta` 
    On e.entity_id = beta.product_id And
       beta.entity_id In (81558, 81559, ... stupidly long list of ids)
    Left Join 
  `catalog_product_entity_int` AS `is_uni` 
    On e.entity_id = is_uni.entity_id And
       attribute_id = 179 
Where 
 is_uni.value = 1 OR 
 beta.product_id IS NOT NULL

If I just have 1 condition in the WHERE clause everything is fine, but with the OR it takes sometimes some minutes to finish and thats way too long. 如果我在WHERE子句中只有1个条件,那么一切都很好,但是使用OR有时需要几分钟才能完成,那太长了。 Which options do I have to get better results? 我必须选择哪些选项才能获得更好的结果? Another problem is that I can't make more queries from this and just join the results together. 另一个问题是我无法从中进行更多查询,而只能将结果结合在一起。 Everything has to be in 1 query. 一切都必须在1个查询中。

When I do an EXPLAIN on the query I get the following result (copied in JSON format for better overview): 当我对查询执行EXPLAIN时,会得到以下结果(以JSON格式复制,以获得更好的概述):

{
        "data":
        [
            {
                "id": 1,
                "select_type": "SIMPLE",
                "table": "e",
                "type": "ALL",
                "possible_keys": "PRIMARY",
                "key": null,
                "key_len": null,
                "ref": null,
                "rows": 213396,
                "Extra": "Using temporary"
            },
            {
                "id": 1,
                "select_type": "SIMPLE",
                "table": "beta",
                "type": "range",
                "possible_keys": "PRIMARY",
                "key": "PRIMARY",
                "key_len": "4",
                "ref": null,
                "rows": 2833,
                "Extra": "Using where; Using index"
            },
            {
                "id": 1,
                "select_type": "SIMPLE",
                "table": "is_uni",
                "type": "ref",
                "possible_keys": "UNQ_CATALOG_PRODUCT_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID_STORE_ID,IDX_CATALOG_PRODUCT_ENTITY_INT_ATTRIBUTE_ID,IDX_CATALOG_PRODUCT_ENTITY_INT_ENTITY_ID",
                "key": "UNQ_CATALOG_PRODUCT_ENTITY_INT_ENTITY_ID_ATTRIBUTE_ID_STORE_ID",
                "key_len": "6",
                "ref": "unc_cpk.e.entity_id,const",
                "rows": 1,
                "Extra": "Using where"
            },
            {
                "id": 1,
                "select_type": "SIMPLE",
                "table": "cat_index",
                "type": "eq_ref",
                "possible_keys": "PRIMARY,IDX_CAT_CTGR_PRD_IDX_PRD_ID_STORE_ID_CTGR_ID_VISIBILITY,15D3C269665C74C2219037D534F4B0DC",
                "key": "PRIMARY",
                "key_len": "10",
                "ref": "const,unc_cpk.e.entity_id,const",
                "rows": 1,
                "Extra": "Using where"
            },
            {
                "id": 1,
                "select_type": "SIMPLE",
                "table": "price_index",
                "type": "eq_ref",
                "possible_keys": "PRIMARY,IDX_CATALOG_PRODUCT_INDEX_PRICE_CUSTOMER_GROUP_ID,IDX_CATALOG_PRODUCT_INDEX_PRICE_WEBSITE_ID",
                "key": "PRIMARY",
                "key_len": "8",
                "ref": "unc_cpk.cat_index.product_id,const,const",
                "rows": 1,
                "Extra": "Using where"
            }
        ]
    }

If each query with one condition is individually fast, try doing 如果每个具有一个条件的查询都很快,请尝试执行

Select
  blah
Where
  is_uni.value = 1
Union
Select
  blah
Where
  beta.product_id Is Not Null

As long as they don't return too many results, this will also be reasonably quick. 只要他们没有返回太多结果,这也将是相当快的。

Or when you said quick with one condition, did you just mean the first? 或者,当您在一个条件下快速说话时,您是说第一个条件吗?

It looks like you need an index on beta.product_id unless this is your primary key there? 看起来您需要在beta.product_idbeta.product_id索引,除非这是您的主键?

Otherwise, you can do this as a Union query each one having a different where clause: 否则,您可以将其作为并集查询来执行,每个查询都有一个不同的where子句:

SELECT DISTINCT `e`.*, `cat_index`.`position` AS `cat_index_position`, `price_index`.`price`, 
   `price_index`.`tax_class_id`, `price_index`.`final_price`, IF(price_index.tier_price IS NOT 
   NULL, LEAST(price_index.min_price, price_index.tier_price),
    price_index.min_price) AS `minimal_price`, `price_index`.`min_price`, 
   `price_index`.`max_price`, `price_index`.`tier_price` 
FROM `catalog_product_entity` AS `e`
 INNER JOIN `catalog_category_product_index` AS `cat_index` ON cat_index.product_id=e.entity_id 
      AND cat_index.store_id=1 AND cat_index.visibility IN(2, 4) AND cat_index.category_id='2'
 INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id 
  AND price_index.website_id = '1' AND price_index.customer_group_id = 0
 LEFT JOIN `beta_entity_product` AS `beta` ON e.entity_id = beta.product_id AND beta.entity_id IN (81558,81559,84592,84593,87758,87759,87760,87761,90944,90945,90946,90947,94364,94365,94366,94367,98458,98459,98460,98461,98462,98463,104194,104195,104196,104197,110151,110152,110153,110154,110155,110156,116583,116584,116585,116586,123366,123367,123368,123369,123370,123371,123372,123373,130500,130501,130502,130503,130504,130505,130506,138075,138076,138077,138078,138079,138080,146179,146180,146181,146182,146183,146184,154543,154544,154545,154546,154547,154548,154549,154550,163639,163640,163641,163642,163643,163644,163645,173998,173999,174000,174001,174002,174003,174004,174005,174006,174007,184545,184546,184547,184548,184549,184550,195249,195250,195251,195252,195253,195254,195255,195256,195257,195258,206400,206401,206402,206403,206404,206405,217632,217633,217634,217635,217636,217637,217638,217639,229029,229030,229031,229032,229033,229034,229035,229036,229037,229038,229039,229040,240350,240351,240352,240353,240354,240355,240356,240357,240358,240359,240360,240361,251631,251632,251633,251634,251635,251636,251637,251638,251639,262900,262901,262902,262903,262904,262905,262906,262907,262908,262909,274205,274206,274207,274208,274209,274210,274211,274212,274213,274214,274215,274216,274217,285747,285748,285749,285750,285751,285752,285753,285754,285755,285756,285757,285758,297747,297748,297749,297750,297751,297752,297753,297754,297755,297756,297757,297758,297759,297760,297761,309660,309661,309662,309663,309664,309665,309666,309667,322314,322315,322316,322317,322318,322319,322320,322321,334814,334815,334816,334817,334818,334819,334820,334821,334822,334823,334824,334825,334826,346810,346811,346812,346813,346814,346815,346816,346817,346818,346819,346820,346821,358550,358551,358552,358553,358554,358555,358556,358557,358558,358559,358560,358561,358562,370376,370377,370378,370379,370380,370381,370382,370383,370384,370385,370386,370387,381938,381939,381940,381941,381942,381943,381944,381945,381946,381947,381948,381949,381950,391081,391082,391083,391084,391085,391086,391087,391088,391089,391090,391091,391092,391093,396111,396112,396113,396114,396115,396116,396117,396118,396119,396120,396121,396122,396123,396124,396125)
 LEFT JOIN `catalog_product_entity_int` AS `is_uni` ON e.entity_id = is_uni.entity_id AND attribute_id = 179 


WHERE is_uni.value = 1 
UNION
SELECT DISTINCT `e`.*, `cat_index`.`position` AS `cat_index_position`, `price_index`.`price`, 
   `price_index`.`tax_class_id`, `price_index`.`final_price`, IF(price_index.tier_price IS NOT 
   NULL, LEAST(price_index.min_price, price_index.tier_price),
    price_index.min_price) AS `minimal_price`, `price_index`.`min_price`, 
   `price_index`.`max_price`, `price_index`.`tier_price` 
FROM `catalog_product_entity` AS `e`
 INNER JOIN `catalog_category_product_index` AS `cat_index` ON cat_index.product_id=e.entity_id 
      AND cat_index.store_id=1 AND cat_index.visibility IN(2, 4) AND cat_index.category_id='2'
 INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id 
  AND price_index.website_id = '1' AND price_index.customer_group_id = 0
 LEFT JOIN `beta_entity_product` AS `beta` ON e.entity_id = beta.product_id AND beta.entity_id IN (81558,81559,84592,84593,87758,87759,87760,87761,90944,90945,90946,90947,94364,94365,94366,94367,98458,98459,98460,98461,98462,98463,104194,104195,104196,104197,110151,110152,110153,110154,110155,110156,116583,116584,116585,116586,123366,123367,123368,123369,123370,123371,123372,123373,130500,130501,130502,130503,130504,130505,130506,138075,138076,138077,138078,138079,138080,146179,146180,146181,146182,146183,146184,154543,154544,154545,154546,154547,154548,154549,154550,163639,163640,163641,163642,163643,163644,163645,173998,173999,174000,174001,174002,174003,174004,174005,174006,174007,184545,184546,184547,184548,184549,184550,195249,195250,195251,195252,195253,195254,195255,195256,195257,195258,206400,206401,206402,206403,206404,206405,217632,217633,217634,217635,217636,217637,217638,217639,229029,229030,229031,229032,229033,229034,229035,229036,229037,229038,229039,229040,240350,240351,240352,240353,240354,240355,240356,240357,240358,240359,240360,240361,251631,251632,251633,251634,251635,251636,251637,251638,251639,262900,262901,262902,262903,262904,262905,262906,262907,262908,262909,274205,274206,274207,274208,274209,274210,274211,274212,274213,274214,274215,274216,274217,285747,285748,285749,285750,285751,285752,285753,285754,285755,285756,285757,285758,297747,297748,297749,297750,297751,297752,297753,297754,297755,297756,297757,297758,297759,297760,297761,309660,309661,309662,309663,309664,309665,309666,309667,322314,322315,322316,322317,322318,322319,322320,322321,334814,334815,334816,334817,334818,334819,334820,334821,334822,334823,334824,334825,334826,346810,346811,346812,346813,346814,346815,346816,346817,346818,346819,346820,346821,358550,358551,358552,358553,358554,358555,358556,358557,358558,358559,358560,358561,358562,370376,370377,370378,370379,370380,370381,370382,370383,370384,370385,370386,370387,381938,381939,381940,381941,381942,381943,381944,381945,381946,381947,381948,381949,381950,391081,391082,391083,391084,391085,391086,391087,391088,391089,391090,391091,391092,391093,396111,396112,396113,396114,396115,396116,396117,396118,396119,396120,396121,396122,396123,396124,396125)
 LEFT JOIN `catalog_product_entity_int` AS `is_uni` ON e.entity_id = is_uni.entity_id AND attribute_id = 179
WHERE beta.product_id IS NOT NULL

Depending on your data and if the OR is mutually exclusive data, you could use an UNION ALL. 根据您的数据,如果OR是互斥数据,则可以使用UNION ALL。 The Query you are running is not able to fully take advantage of an INDEX MERGE that would be required to make it run fast with the OR statement. 您正在运行的查询不能完全利用INDEX MERGE,而使用OR语句使其快速运行将需要它。

There are multiple solutions: 有多种解决方案:

1) Split query and use UNION - possible sorting and pagination problems 2) Add new property that will be used only for this filter so instead of 1)拆分查询并使用UNION-可能存在排序和分页问题2)添加仅将用于此过滤器的新属性,而不是

is_uni.value = 1 OR beta.product_id IS NOT NULL is_uni.value = 1或beta.product_id不为空

you would be querying only 你只会查询

feature_filter = 1 feature_filter = 1

3) Decompose query into multiple queries - I would suggest this as first step since queries as big as this one are really great way to shoot yourself in the foot 3)将查询分解为多个查询-我建议您将其作为第一步,因为与该查询一样大的查询确实是击掌的好方法

BTW. 顺便说一句。 Using distinct on query with so many columns eats a lot of resources (mysql needs to compare each column value!) 对这么多列使用不重复查询会消耗大量资源(mysql需要比较每个列的值!)

Suggestions: 意见建议:

1.) Instead of 1.)代替

beta.product_id IS NOT NULL

write

not (beta.product_id IS NULL)

2.) You can create a stored procedure or a stored function if you want a single request for your query. 2)如果您需要一个查询请求,则可以创建一个存储过程或一个存储函数。 Of course you can use multiple queries and at the end merge the partial results using a single database server request. 当然,您可以使用多个查询,最后使用单个数据库服务器请求合并部分结果。

3.) If you have complex db logics, use an ORM , like Flourish . 3.)如果您具有复杂的数据库逻辑,请使用ORM ,例如Flourish

I wish you good luck. 祝你好运。

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

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