2013-11-13 3 views
2

Позвольте мне сказать, прежде всего, что я не гуру mySQL; в то время как я использую его адекватно, я не знаю много подробностей об этом. В системе, которую я только что унаследовал, я получил этот запрос:MySQL: оптимизация запроса с NOT EXISTS a подзапрос

SELECT DISTINCT profile2.f3 
FROM node AS profile 
     JOIN node AS profile2 
     ON (profile.f1 = profile2.f1) 
WHERE profile.f2 = "aString" 
     AND profile.f3 = "anotherString" 
     AND profile2.f2 = "aThirdString" 
     AND NOT EXISTS (SELECT profile3.f1 
         FROM node AS profile3 
         WHERE profile3.f1 = profile.f1 
           AND profile3.f2 = "yetAnotherString") ; 

SHOW CREATE TABLE дает:

CREATE TABLE `node` (
    `id` bigint(20) NOT NULL AUTO_INCREMENT, 
    `graph` varchar(100) CHARACTER SET latin1 DEFAULT NULL, 
    `f1` varchar(200) NOT NULL, 
    `f2` varchar(200) NOT NULL, 
    `f3` mediumtext NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `nodeindex` (`graph`(20),`f1`(100),`f2`(100),`f3`(100)), 
    KEY `ix_node_f1` (`f1`), 
    KEY `ix_node_graph` (`graph`), 
    KEY `ix_node_f3` (`f3`(255)), 
    KEY `ix_node_f2` (`f2`), 
    KEY `node_po` (`f2`,`f3`(130)), 
    KEY `node_so` (`f1`,`f3`(130)), 
    KEY `node_sp` (`f1`,`f2`(130)), 
    FULLTEXT KEY `node_search` (`f3`) 
) ENGINE=MyISAM AUTO_INCREMENT=455854703 DEFAULT CHARSET=utf8 

EXPLAIN EXTENDED дает:

+----+--------------------+----------+------+--------------------------------------------------------------------------------------+---------+---------+-----------------------------------+-------+----------+------------------------------+ 
| id | select_type  | table | type | possible_keys                  | key  | key_len | ref        | rows | filtered | Extra      | 
+----+--------------------+----------+------+--------------------------------------------------------------------------------------+---------+---------+-----------------------------------+-------+----------+------------------------------+ 
| 1 | PRIMARY   | profile | ref | ix_node_f1,ix_node_f3,ix_node_f2,node_po,node_so,node_sp,node_search     | node_po | 994  | const,const      | 49084 | 100.00 | Using where; Using temporary | 
| 1 | PRIMARY   | profile2 | ref | ix_node_f1,ix_node_f2,node_po,node_so,node_sp          | node_sp | 994  | sumazi_prdf.profile.f1,const  |  1 | 100.00 | Using where     | 
| 2 | DEPENDENT SUBQUERY | profile3 | ref | ix_node_f1,ix_node_f2,node_po,node_so,node_sp          | node_sp | 994  | sumazi_prdf.profile.f1,const  |  1 | 100.00 | Using where     | 
+----+--------------------+----------+------+--------------------------------------------------------------------------------------+---------+---------+-----------------------------------+-------+----------+------------------------------+ 

Как я уже говорил, я не RDBMS, но моя интуиция подсказывает, что производительность этого запроса может быть существенно улучшена. Какие-либо предложения?

+1

Вы хотите выбрать только столбец 'profile2.f3'? Кроме того, добавьте 'SHOW CREATE TABLE node;' вывод в вопрос. –

+0

«EXPLAIN» запроса также будет полезен. –

+0

Самообслуживание плюс анти-соединение. Позвольте мне угадать: модель EAV? – wildplasser

ответ

1

Вы можете попробовать это, и это должно быть относительно быстрее, или вы можете пойти для соединений

SELECT DISTINCT profile2.f3 
    FROM node AS profile 
      JOIN node AS profile2 
      ON (profile.f1 = profile2.f1) 
    WHERE profile.f2 = "aString" 
      AND profile.f3 = "anotherString" 
      AND profile2.f2 = "aThirdString" 
      AND PROFILE.F1 NOT IN (SELECT profile3.f1 
          FROM node AS profile3 
          WHERE profile3.f2 = "yetAnotherString") ; 
+1

Почему это было бы быстрее? –

+0

Поскольку NOT IN строит результирующий набор и исключает значение, но NOT EXISTS работает как Joins, а затем исключает. – Santhosh

1

левый JOINS ... Где NULL имеют тенденцию быть быстрее, чем не Exists положений в MySQL; в других СУБД, это, как правило, наоборот. Попытка:

SELECT DISTINCT profile2.f3 
FROM node AS profile 
JOIN node AS profile2 ON profile.f1 = profile2.f1 
LEFT JOIN node AS profile3 ON profile.f1 = profile3.f1 
        AND profile3.f2 = "yetAnotherString" 
WHERE profile.f2 = "aString" 
    AND profile.f3 = "anotherString" 
    AND profile2.f2 = "aThirdString" 
    AND profile3.f1 IS NULL 
+0

'LEFT' присоединяется? Вы пропустили его в коде. –

+0

@ypercube: D'oh! Спасибо - ответ исправлен. –

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