2016-12-11 3 views
0

У меня есть таблица поло, как это:Оптимизация выберите строки на основе предыдущего выбора результата

product_id |aid |value| 
------------|-------|-----| 
789   |6  |1 | 
789   |6  |3 | -->aid = 6 , value = 3 
789   |  8| 8| -->rows that i want with aid 8 
789   |  8| 11| -->rows that i want with aid 8 
789   |  8| 82| -->rows that i want with aid 8 
------------|-------|-----| 
790   |6  |2 | 
790   |6  |3 | -->aid = 6 , value = 3 
790   |6  |4 | 
790   |  8| 8| -->rows that i want with aid 8 
790   |  8| 16| -->rows that i want with aid 8 
------------|-------|-----| 
791   |6  |7 | 
791   |8  |13 | 
------------|-------|-----| 

Я хочу все строки с помощью = 8 для конкретных продуктов, которые имеют пару (помощь = 6 и значения = 3) что я сделал: Сначала я выбираю отдельные товарные_имени, имеющие aid = 6 и value = 3.
Затем я выбираю все строки с помощью, где product_ids находятся в предыдущем запросе select. вот мой запрос, который занимает около 1 секунды.

SELECT DISTINCT `value` FROM `fields` 
WHERE aid = 8 AND product_id IN 
(
    SELECT DISTINCT `fields`.product_id FROM `fields` 
    WHERE aid = 6 AND `value` = 3 
) 

результат значение 8,11,82,16
есть более оптимизированный способ сделать это?

+0

Каков объем ваших данных? –

+0

@GordonLinoff ~ 700K строк в полях – osyan

+0

И насколько велика количество совпадающих строк (до отдельных)? –

ответ

1

Во-первых, distinct в подзапросе должно быть ненужным. Я не уверен, что MySQL оптимизирует его. Итак, начнем с:

SELECT DISTINCT f.`value` 
FROM `fields` f 
WHERE f.aid = 8 AND 
     f.product_id IN (SELECT f2.product_id 
         FROM `fields` f2 
         WHERE f2.aid = 6 AND f2.`value` = 3 
        ); 

Для этого запроса, вы хотите индекс на fields(aid, value, product_id).

В более ранних версиях MySQL было бы лучше заменить подзапрос IN на EXISTS. Если ваш запрос заканчивается через одну секунду, то вы, вероятно, находитесь на более поздней версии.

+0

спасибо, примерно на 7% лучше, но мне нужно что-то более оптимизированное, если оно может быть – osyan

+0

да 'IN' и' EXISTS' имеют такую ​​же производительность – osyan

+0

@osyan. , , У вас есть именно этот 3-компонентный индекс? –

0

Гордон показал вам IN метод вы можете также рассмотреть вопрос о EXISTS и или JOIN методов, если вы в конечном итоге необходимости настройки производительности все три имеют различные преимущества и недостатки, в зависимости от размера данных и сложности.

EXISTS просто использует коррелированный подзапросом

SELECT f.* 
FROM 
    `fields` f 
WHERE 
    f.aid = 8 
    EXISTS (
     SELECT 1 
     FROM `fields` f2 
     WHERE 
      f2.aid = 6 
      AND f2.`value` = 3 
      AND f1.product_id = f2.product_id) 

Для метода присоединения, сохраняя отличие в этом случае будет делать, так как если 6 & 3 может быть представлен более чем один раз.

SELECT f.* 
FROM 
    `fields` f 
    INNER JOIN (
     SELECT DISTINCT `fields`.product_id FROM `fields` 
     WHERE aid = 6 AND `value` = 3 
    ) t 
    ON f.product_id = t.product_i 
WHERE 
    f.aid = 8 
+0

Получение 1.6 И 2.3 Секунды с этими двумя методами – osyan

+0

@osyan Я видел ваши комментарии к Grodon's и здесь, я думаю, я пропустил часть об оптимизации, если IN и EXISTS выполняют то же самое, что было бы интересно, но это говорит о том, что результаты подзапроса не крошечные и не огромные. http://stackoverflow.com/questions/14190788/subqueries-with-exists-vs-in-mysql Но IN, EXISTS, JOIN - это 3 способа, поэтому, если вам нужно оптимизировать его больше, чем 1.6, вам могут понадобиться индексы или любое количество других вещей. объясните план и отправьте сообщение, чтобы другие могли прокомментировать, иначе мы не знаем, что происходит в вашей среде. – Matt

0

Сначала добавьте следующий указатель в таблицу, если у вас его еще нет.

ALTER TABLE fields ADD KEY (aid, product_id, value); 

Кстати, задавая вопросы SQL, это поможет, если вы разместите вывод SHOW CREATE TABLE таким образом, мы можем увидеть, если вы уже определили никаких индексов или ограничений.

sql> SHOW CREATE TABLE fields\G 
     Table: fields 
Create Table: CREATE TABLE `fields` (
    `product_id` int(11) DEFAULT NULL, 
    `aid` int(11) DEFAULT NULL, 
    `value` int(11) DEFAULT NULL, 
    KEY `aid` (`aid`,`product_id`,`value`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

Далее, попробуйте этот запрос:

SELECT DISTINCT f1.value 
FROM fields AS f1 
INNER JOIN fields AS f2 
    ON f1.product_id=f2.product_id 
WHERE f1.aid=8 AND f2.aid=6 AND f2.value=3; 

Это не использует подзапросы, только индексированный поиск. Мы не заботимся о сокращении набора совпадающих строк в f2, потому что в любом случае по-прежнему будет заботиться DISTINCT.

Выход (проверено на MySQL 8.0.0-DMR):

+-------+ 
| value | 
+-------+ 
|  8 | 
| 11 | 
| 82 | 
| 16 | 
+-------+ 

Вот EXPLAIN отчет, чтобы показать оптимизации:

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: f2 
    partitions: NULL 
     type: ref 
possible_keys: aid 
      key: aid 
     key_len: 5 
      ref: const 
     rows: 6 
    filtered: 10.00 
     Extra: Using where; Using index; Using temporary 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: f1 
    partitions: NULL 
     type: ref 
possible_keys: aid 
      key: aid 
     key_len: 10 
      ref: const,test.f2.product_id 
     rows: 2 
    filtered: 100.00 
     Extra: Using index 

Обе таблицы получить "Использование индекса" оптимизации, поэтому они используют индекс покрытия.

Обе таблицы используют индексный поиск, чтобы сузить количество исследуемых строк.

Есть еще временная таблица, которая вызывает некоторые накладные расходы. Но это неизбежно из-за DISTINCT. Но по крайней мере, это только одна временная таблица, а не несколько временных таблиц из-за использования DISTINCT в подзапросе. И таблица temp должна быть небольшой, так как ей нужно только сохранить строки, которые уже были сопоставлены.

+0

благодарит ваших рекомендаций. но результат будет иметь дополнительное значение 13, исходящее из последней строки таблицы полей. но поскольку последний продукт не имеет строки с 'help = 6, value = 3', то результат не должен содержать 13 – osyan

+0

У меня также есть индекс на' help, product_id, value'. я просто хочу, чтобы это было просто для большей читаемости – osyan

+1

Я протестировал запрос, который я разместил выше, используя данные примера, которыми вы делились. Я не получил 13 результатов. Если вам 13, значит, вы должны были протестировать либо разные данные, либо другой запрос. –

Смежные вопросы