Improve MySQL Query with IN Subquery

你离开我真会死。 提交于 2020-01-02 05:23:11

问题


I hava a table items and a table item_attributes.

For simplicity let's say my table item has a column id and a column name. Of cource there is a index on the id column.

the item_attributes table has the columns id, item_id, attribute_name and attribute_value and an index ON attrubute_name

Now I want to query all items with a specific attribut without using a join.

I do this with the following query:

SELECT *
FROM items i
WHERE i.id IN (
    SELECT item_id
    FROM item_attributes a
    WHERE a.attribute_name = 'SomeAttribute'
      AND a.attribute_value = 'SomeValue'
)

the SubQuery itself runs fast.

If I execute the query itself first and use the result for an IN query

SELECT *
FROM items i
WHERE i.id IN (1,3,5,7,10,...)

it is fast, too.

However, combined the query is very, very slow (>2 secs.) If I investigate the query plan I see why: MySQL does a full table scan on the items table instead of executing the subquery first and using the result for an index query.

1, 'PRIMARY', 'items', 'ALL', '', '', '', '', 149726, 'Using where'
2, 'DEPENDENT SUBQUERY', 'item_attributes', 'index_subquery', 'IDX_ATTRIBUTE_NAME', 'IDX_ATTRIBUTE_NAME', '4', 'func', 1, 'Using where'

Is there a way to optimize this query? I know that the subquery will always return only a small resultset (<100 rows).


回答1:


MySQL cannot switch the leading and the driven table in the IN clause. This is going to be corrected in 6.0.

For now, you can rewrite it like this (requires a JOIN):

SELECT  i.*
FROM    (
        SELECT  DISTINCT item_id
        FROM    item_attributes a
        WHERE   a.attribute_name = 'SomeAttribute'
                AND a.attribute_value = 'SomeValue'
        ) ai
JOIN    items i
ON      i.id = ai.item_id

Since you are using the EAV model you may want to make a unique index on (attribute_name, item_id) in which case you can use a plain join:

SELECT  i.*
FROM    item_attributes ai
JOIN    items i
ON      i.id = ai.item_id
WHERE   a.attribute_value = 'SomeValue'
        AND a.attribute_name = 'SomeAttribute'



回答2:


inner join does better and more efficient

select i.* 
from items i
inner join item_attributes ia on i.id=ia.item_id
where ia.attribute_name='SomeAttribute' AND ia.attribute_value='SomeValue';

if the primary key for item_attributes is for item_id+attribute_name,
then no GROUP BY is required




回答3:


You can use an exists

SELECT *
FROM items i
WHERE Exists
(
    SELECT item_id
    FROM item_attributes a
    WHERE 1=1
      AND i.id = a.ItemId
      AND a.attribute_name = 'SomeAttribute'
      AND a.attribute_value = 'SomeValue'
)



回答4:


SELECT DISTINCT i.*
FROM items i, item_attributes ai
WHERE i.id = ai.item_id AND a.attribute_name = 'SomeAttribute' AND a.attribute_value = 'SomeValue'


来源:https://stackoverflow.com/questions/7065062/improve-mysql-query-with-in-subquery

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!