Оптимизируйте SQL с подзапросом из

Я хотел бы оптимизировать оператор SQL, ниже приведен оригинальный.

SELECT DISTINCT
    p.productID,
    p.filename,
    p.model,
    p.code,
    p.manufacturerID,
    f2.manufacturerName,
    m.manufacturerName,
    CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
            CAST(p.productID AS CHAR),
            ', \'',
            f2.manufacturerName,
            '\', \'',
            f2.code,
            '\', \'',
            f2.denumire,
            '\') ;') INS
FROM
    (SELECT 
        f.manufacturerName, f.categoryName, f.code, f.denumire, f.code_2
    FROM
        furnizorlist f
    LEFT JOIN distribitems d ON 
        (d.manufacturer = f.manufacturerName
        AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450))
    WHERE
        productID IS NULL) f2,
    products p,
    manufacturers m
WHERE
    f2.code_2 <> ''
        AND (f2.code_2 = p.code_2 OR f2.code_2 = p.model_2)
        AND p.manufacturerID = m.manufacturerID
        AND m.manufacturerName = f2.manufacturerName
        AND m.manufacturerName != 'Compatibil'
        AND p.code != '1'
ORDER by p.filename ASC;    

На моем ПК это занимает около 34 секунд.

скриншот

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

Вот мой невероятно быстрый SQL:

SELECT DISTINCT
    p.productID,
    p.filename,
    p.model,
    p.code,
    p.manufacturerID,
    f.manufacturerName,
    m.manufacturerName,
    CONCAT('INSERT INTO distribItems(productID, manufacturer, code, distributorText) VALUES (',
            CAST(p.productID AS CHAR),
            ', \'',
            f.manufacturerName,
            '\', \'',
            f.code,
            '\', \'',
            f.denumire,
            '\') ;') INS
FROM
    furnizorlist f,
    distribitems d,
#subquery end
    products p,
    manufacturers m
WHERE
    d.manufacturer = f.manufacturerName
        AND (d.code = f.code OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450)
        AND d.productID IS NULL
#subquery condions end (f and d tables)
# the next is a subquery result:
        AND f.code_2 <> ''
        AND (f.code_2 = p.code_2 OR f.code_2 = p.model_2)
        AND p.manufacturerID = m.manufacturerID
        AND m.manufacturerName = f.manufacturerName
        AND m.manufacturerName != 'Compatibil'
        AND p.code != '1'
ORDER by p.filename ASC;    

Если я напишу explain improved_sql, я увижу столбец Impossible WHERE. Я пытался, но не мог найти, почему это невозможно. Я проверил совместимость полей: чтобы не было случая, когда требуется сравнить int с varchar и тому подобное. Я не смог найти какой-либо серьезной ошибки, поэтому я здесь.

Есть ли логическая ошибка в предложении WHERE? например, попросить поле быть 1, а затем 2?

Поля, которые заканчиваются на ID, являются INT Поля, которые заканчиваются на NAME, code являются varchar (255) Поля с Text имеют 450 и 8192 varchar (используется только в одном месте)

перевод: "denumire" означает "описание" - или что-то в этом роде :)

Не уверен, какая версия mysql работает на стороне сервера, возможно, 5.

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

РЕДАКТИРОВАТЬ:

Невозможное, откуда оно взялось:

EXPLAIN 

SELECT 
    f.manufacturerName,
    f.categoryName,
    f.code,
    f.denumire,
    f.code_2
FROM
    furnizorlist f
        INNER JOIN
    distribitems d ON (d.manufacturer = f.manufacturerName
        AND (d.code = f.code
        OR d.manufacturer LIKE 'DELL')
        AND d.distributorText = LEFT(f.denumire, 450))
WHERE
    productID IS NULL

Примечание: ВНУТРЕННЕЕ СОЕДИНЕНИЕ, а не ЛЕВОЕ СОЕДИНЕНИЕ.

Edit2: Таблица: furnizorlist 42 751 запись Таблица: distribitems 72 290 записей


person Community    schedule 14.10.2012    source источник
comment
1) Вы изменили left join на inner join 2) Вы получаете такое же сообщение с первым sql?   -  person Olaf Dietsche    schedule 14.10.2012
comment
у обоих теперь пустой результат, так что да :) - но не заметил важности левого соединения, спасибо   -  person    schedule 14.10.2012
comment
23087 записей в подзапросе как LEFT JOIN, а 0 как INNER JOIN... вот почему так быстро? :) и оттуда приходит Невозможное ОТКУДА (объясните ‹подзапрос›)   -  person    schedule 14.10.2012


Ответы (1)


Не совсем уверен, но вот несколько моментов, которые многим помогают, если вы собираетесь использовать внутреннюю таблицу (вы первый пример) - вам действительно нужно попытаться сузить то, что она оттягивает. Это может означать написание некоторых избыточных предложений where. Например, «где order_dt находится между 2001 и 2002» может оказаться в меньшей внутренней таблице И в основном запросе. Почему? Потому что в некоторых ситуациях внутреннюю таблицу нельзя оптимизировать, что приводит к тому, что сервер временно извлекает миллионы строк только для тех немногих, которые вам нужны.

Кроме того, я заметил строковую функцию в одном из ваших объединений "LEFT(f.denumire, 450))"

Во время соединения следует избегать любых функций, это заставляет сервер (одну за другой) оценивать каждую запись... он не может оптимизировать. Это в некоторой степени похоже на то, почему вы всегда должны использовать первичные ключи для соединения, но требует больше времени. Лучше придерживаться «как» = И, НЕ, ИЛИ, В и т.

person Community    schedule 01.11.2012
comment
Спасибо, попробую после обеда - person ; 01.11.2012