производительность запросов MySQL - PullRequest
1 голос
/ 29 июля 2009

Может кто-нибудь дать подсказку об этом? :

У меня есть таблица, скажем, tblA, где у меня есть id1 и id2 как столбцы и индекс (id1, id2). Я хочу выбрать id1, где id2 принадлежат нескольким наборам. Поэтому я хотел бы сказать

select id1 from tblA 
where id2 in (val1,val2,val3 ...)
union
select id1 from tblA 
where id2 in (val4,val2,val3 ...)
union
(...)*

Допустим, у нас есть в таблице A следующее:

(1,1)
(1,2)
(1,3)
(1,4)
(1,5)
(2,1)
(2,2)
(2,3)

Теперь я хочу, чтобы все id1 имели id2 in (3,4).

Итак, что я хочу получить, это id1 = 1.

2 не должно появляться, потому что, хотя у нас есть отношение (2,3), у нас нет (2,4).

Есть идеи, как выполнить этот запрос? Я полагаю, что описанный выше способ имеет проблему с производительностью, если (...) сильно возрастает !? Спасибо.

приветствует

Ответы [ 6 ]

1 голос
/ 31 июля 2009

Вы должны создать временную таблицу следующим образом:

CREATE TABLE temp (id INT NOT NULL PRIMARY KEY) ENGINE MEMORY;

, заполните его значениями, которые вы ищете (2 и 3 в вашем примере):

INSERT
INTO    temp
VALUES  (3), (4)

и выполните этот запрос:

SELECT  ad.id1
FROM    (
        SELECT  DISTINCT id1
        FROM    a
        ) ad
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    temp
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    a
                WHERE   a.id1 = ad.id1
                        AND a.id2 = temp.id
                )
        )

Вы должны создать составной индекс на (id1, id2), чтобы это работало.

Для каждого id1 это будет проверять каждый id2 против temp не более одного раза и будет возвращать false, как только будет найден первый id2, отсутствующий в temp для каждого id1.

Вот план запроса:

1, 'PRIMARY', '<derived2>', 'ALL', '', '', '', '', 2, 'Using where'
3, 'DEPENDENT SUBQUERY', 'temp', 'ALL', '', '', '', '', 2, 'Using where'
4, 'DEPENDENT SUBQUERY', 'a', 'eq_ref', 'PRIMARY', 'PRIMARY', '8', 'ad.id1,test.temp.id', 1, 'Using index'
2, 'DERIVED', 'a', 'range', '', 'PRIMARY', '4', '', 3, 'Using index for group-by'

, нет temporary, нет filesort.

0 голосов
/ 31 июля 2009

Вам необходимо создать отдельный индекс для столбца 'id2', поскольку комбинированный индекс для (id1, id2) не будет использоваться при поиске только для id2.

Этот запрос делает то, что вы упомянули

SELECT id1 FROM tblA WHERE id2 IN (?,?,?,?)
GROUP BY id1 HAVING COUNT(id2)=4

ПРИМЕЧАНИЕ. Необходимо настроить условие COUNT (id2) в предложении HAVING на количество значений, указанных в предложении IN. Здесь я использовал четыре? для представления четырех значений, поэтому я написал COUNT (id2) = 4.

Для сценария, который вы упомянули в комментарии, запрос будет выглядеть следующим образом

SELECT id1 FROM tblA WHERE id2 IN (3,4)
GROUP BY id1 HAVING COUNT(id2)=2
0 голосов
/ 30 июля 2009

Но все эти запросы возвращают оба идентификатора из столбца id1! Я думаю, что Роберт имел в виду, что в результате он просто хочет «1» из столбца id1:

   id1 id2
    1 | 1
    1 | 2
    1 | 3
    1 | 4  -->  id1s that have id2 with 3 and 4
    1 | 5
    2 | 1
    2 | 2
    2 | 3

Поскольку id1 = 2 не имеет 3 И 4, это не должно быть результатом.

Пожалуйста, поправьте меня, если я неправильно понял ... Я пытался сделать заявление, но я не мог вернуть только id1 = 1, но я также очень заинтересован в эффективном решении этого вопроса!

0 голосов
/ 29 июля 2009

Во-первых, помните, что

select id1 from tblA where id2 in (val1, val2, val3) union
select id1 from tblA where id2 in (val4, val5, val6)

должен дать тот же результат, что и

select id1 from tblA where id2 in (val1, val2, val3, val4, val5, val6)

так что вы, возможно, сможете повысить эффективность, сформулировав один запрос, а не используя объединение.

Во-вторых (и независимо от вышесказанного) вы должны добавить индекс на id2 в таблицу tblA. Без этого значения id2 случайным образом распределяются как по существующему индексу, так и по данным таблицы, поэтому оптимизатору не останется ничего другого, кроме как выполнить линейное сканирование индекса, если вам повезет.

0 голосов
/ 29 июля 2009

Можете ли вы объединить все наборы в один большой набор?

Если порядок не важен, это может показаться самым быстрым способом.

0 голосов
/ 29 июля 2009

Союз убьет ваше выступление. Используйте что-то вроде этого:

select id1 from tblA where id2 in (val1,val2,val3 ...) or id2 in (val4,val2,val3)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...