문제

I'm have a question. The following query is taking upwards of 2 - 3 seconds to exicute and I'm not sure why. I have 2 tables involved one with a list of items and the another with a list of attribute's for each item. The items table is indexed with unique primary key and the attributes table has a foreign key constraint.

The relationship between the items table is ONE TO MANY to the attributes.

I am not sure how else to speed up query and would appreciate any advice.

The database is MYSQL inodb

EXPLAIN SELECT * FROM eshop_items AS ite WHERE (SELECT attValue FROM eshop_items_attributes WHERE attItemId=ite.ItemId ANd attType=5 AND attValue='20')='20' ORDER BY itemAdded DESC LIMIT 0, 18;

id | select_type        | table                  | type | possible_keys | key       | key_len | ref                    | rows  | Extra
1   PRIMARY               ite                       ALL         NULL        NULL        NULL    NULL                     57179   Using where; Using   filesort
2   DEPENDENT SUBQUERY  eshop_items_attributes      ref     attItemId       attItemId    9      gabriel_new.ite.itemId      5    Using where

Index: eshop_items_attributes

Name        Fieldnames  Index Type  Index method
attItemId   attItemId   Normal      BTREE
attType     attType     Normal      BTREE
attValue    attValue    Normal      BTREE

Index: eshop_items

Name            Fieldnames      Index Type  Index method
itemCode        itemCode        Unique      BTREE
itemCodeOrig    itemCodeOrig    Unique      BTREE
itemConfig      itemConfig      Normal      BTREE
itemStatus      itemStatus      Normal      BTREE

Can't use a join because the item_attributes table is a key -> value pair table. So for every record in the items_attributes table there can be many item id's

here is a sample

item_id    attribute_index   attribute_value
12345      10                true
12345      2                 somevalue
12345      6                 some other value
32456      10                true
32456      11                another value
32456      2                 somevalue

So a join wouldn't work because I can't join multiple rows from the items_attributes table to one row in the items table.

I can't write a query where attribute_index is = to 2 AN attribute_index = 10. I would always get back no results.

:(

도움이 되었습니까?

해결책

Change the query from correlated to IN and see what happens.

SELECT * 
  FROM eshop_items AS ite 
 WHERE ItemId IN (
       SELECT attItemId
         FROM eshop_items_attributes 
        WHERE attType=5 
          AND attValue='20')
 ORDER BY itemAdded DESC 
 LIMIT 0, 18 

You'll see further gains by changing your btree to bitmap on eshop_items_attributes. But be warned: bitmap has consequences on INSERT/UPDATE.

다른 팁

The "DEPENDENT SUBQUERY" is what's killing performance in this query. It has to run the subquery once for every distinct ItemId in the outer query. It should be much better as a join:

SELECT ite.* FROM eshop_items AS ite 
INNER JOIN eshop_items_attributes AS a ON ite.ItemId = a.attItemId
WHERE a.attType = 5 AND a.attValue = 20
ORDER BY ite.itemAdded DESC LIMIT 0, 18;

I find it much easier to think about such a query as a join:

SELECT ite.*
FROM eshop_items ite join
     eshop_items_attributes ia
     on ia.attItemId = ite.ItemId and
        ia.attType = 5 and
        ia.attValue='20'
ORDER BY ite.itemAdded DESC
LIMIT 0, 18;

This works if there is at most one matching attribute for each item. Otherwise, you need select distinct (which could hurt performance, except you are already doing a sort).

To facilitate this join, create the index eshop_items_attributes(attType, attValue, attItemId). The index should satisfy the join without having to read the table, the rest is dealing with the result set.

The same index would probably help with the correlated subquery.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top