Как я могу сделать этот запрос MySQL (с подзапросом) быстрее?

Вот описание каждого из них, за которым следует образец реального мира.

  • Манекен - просто фиктивные значения, чтобы удовлетворить API. Пример : Если вы тестируете метод класса, который требует много обязательных параметров в конструкторе, который не имеет эффекта в вашем тесте, тогда вы можете создать фиктивные объекты для цель создания новых экземпляров класса.
  • Fake - создать тестовую реализацию класса, который может иметь зависимость от некоторой внешней инфраструктуры. (Хорошая практика заключается в том, что ваш модульный тест НЕ взаимодействует с внешней инфраструктурой.) Пример : Создайте поддельную реализацию для доступа к базе данных, замените ее на коллекцию in-memory.
  • Методы переопределения заглушек для возврата жестко заданных значений, также называемых state-based. Пример : ваш тестовый класс зависит от метода Calculate(), который занимает 5 минут. Вместо того, чтобы ждать 5 минут, вы можете заменить его реальную реализацию заглушкой, которая возвращает жестко заданные значения; занимая лишь небольшую часть времени.
  • Mock - очень похоже на Stub, но interaction-based, а не на состояние. Это означает, что вы не ожидаете, что Mock вернет некоторое значение, но предположим, что выполняется конкретный порядок вызовов методов. Пример. Вы тестируете класс регистрации пользователя. После вызова Save он должен вызвать SendConfirmationEmail.

Stubs и Mocks на самом деле являются подтипами Mock, и реальная реализация swap с тестовой реализацией, но по разным конкретным причинам.

0
задан Steveo 16 January 2019 в 10:36
поделиться

3 ответа

Первое, что нужно сделать, это проверить, есть ли у вас правильные индексы во всех столбцах, где вы ВСТРЕТИЛИСЬ и где вы фильтруете. Обычно отсутствие индексов является причиной медленных запросов.

Если вы хотите пойти дальше, я бы перестроил индексы. Возможно, некоторая фрагментация также замедляет процесс.

Хотя это и не обязательно, вы также можете попробовать перенести ключи, такие как wc-complete, wc-processing, в свою собственную таблицу и выполнить соединения с помощью INT.

Вы также можете попытаться нормализовать SUM или даже создать вычисляемый столбец для них.

0
ответ дан Carlos Alves Jorge 16 January 2019 в 10:36
поделиться

Шаг 1: Создайте читаемые псевдонимы и переместите meta_key -предикаты в JOIN с

Я позволил себе отформатировать ваш запрос для ясности.

Я переименовал псевдонимы и переместил meta_key -предикаты из WHERE в JOIN с:

SELECT
    (SELECT meta_value
        FROM `myprefix_postmeta` as postmeta 
        WHERE 
            postmeta.meta_key = '_sku' 
            AND postmeta.post_id = IM3.meta_value ) AS sku,
    I.order_item_name AS title,
    SUM (IM.meta_value ) AS quantity,
    SUM (IM2.meta_value ) AS total
FROM 
    `myprefix_woocommerce_order_items` AS I
    LEFT JOIN `myprefix_posts` AS posts 
    ON posts.ID = I.order_id
    LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM -- Make readable aliases
        ON IM.order_item_id = I.order_item_id 
            AND IM.meta_key = '_qty'   -- Move predicates from WHERE
    LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM2 
        ON IM2.order_item_id =   I.order_item_id
            AND IM2.meta_key = '_line_total' -- Move predicates from WHERE
    LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM3 
        ON IM3.order_item_id =   I.order_item_id
            AND IM3.meta_key = '_product_id' -- Move predicates from WHERE
WHERE 
    posts.post_type = 'shop_order'
    AND posts.post_status IN
    ( 'wc-completed', 'wc-processing', 'wc-on-hold' )
GROUP BY 
    IM3.meta_value
ORDER BY 
    total DESC

Теперь у нас есть абсолютно эквивалентный запрос.

Давайте посмотрим, что мы можем сделать дальше.

  1. 3 LEFT JOIN с myprefix_woocommerce_order_itemmeta с тем же предикатом IM.order_item_id = I.order_item_id выглядит ненужным дублированием
  2. Но у нас есть разные предикаты на meta_key

Step 2: Заменить 3 JOIN только одним, заменить JOINed-поля CASE-выражениями

Таким образом, мы можем:

a. Замените 3 СОЕДИНЕНИЯ только одним СОЕДИНЕНИЕМ

b. Замените поля IM / IM2 / IM3 CASE-выражениями

SELECT
    (SELECT meta_value
        FROM `myprefix_postmeta` as postmeta 
        WHERE 
            postmeta.meta_key = '_sku' 
            AND postmeta.post_id = ( -- Substitute meta_value with CASE-expressions 
                    CASE
                        WHEN IM.meta_key = '_product_id' THEN IM.meta_value
                        ELSE NULL
                    END 
                ) -- IM3.meta_value               
            ) AS sku,
    I.order_item_name AS title,
    SUM (
        CASE -- Substitute meta_value with CASE-expressions 
            WHEN IM.meta_key = '_qty' THEN IM.meta_value
            ELSE 0 
        END 
    ) AS quantity
    -- IM2.meta_value ) AS total
SUM ( -- Substitute meta_value with CASE-expressions 
    CASE
            WHEN IM.meta_key = '_line_total' THEN IM.meta_value
            ELSE 0
    END 
) AS total       

FROM 
    `myprefix_woocommerce_order_items` AS I
    LEFT JOIN `myprefix_posts` AS posts 
    ON posts.ID = I.order_id
    LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM -- Make readable aliases
        ON IM.order_item_id = I.order_item_id 
            AND IM.meta_key IN ('_qty', '_line_total', '_product_id')
    --         AND IM.meta_key = '_qty'   -- Move predicates from WHERE
    -- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM2 
    --     ON IM2.order_item_id =   I.order_item_id
    --         AND IM2.meta_key = '_line_total' -- Move predicates from WHERE
    -- LEFT JOIN `myprefix_woocommerce_order_itemmeta` AS IM3 
    --     ON IM3.order_item_id =   I.order_item_id
    --         AND IM3.meta_key = '_product_id' -- Move predicates from WHERE
WHERE 
    posts.post_type = 'shop_order'
    AND posts.post_status IN
    ( 'wc-completed', 'wc-processing', 'wc-on-hold' )
GROUP BY 
    (
        CASE
            WHEN IM.meta_key = '_product_id' THEN IM.meta_value
            ELSE NULL
        END 
    ) -- IM3.meta_value    
ORDER BY 
    total DESC

PS

Не очень удобно писать SQL без данных.

И возможно, что этот запрос некорректен для каждой версии mysql.

Поэтому постарайтесь понять принципы, а не просто скопировать и вставить мой код.

Сообщите нам о результатах или проблемах.

0
ответ дан Alex Yu 16 January 2019 в 10:36
поделиться

Если woocommerce является ответвлением WordPress, то они, вероятно, плохо справились с индексацией myprefix_woocommerce_order_itemmeta. Адаптировать подсказки в здесь для улучшения производительности.

Я согласен с другими - шаблон схемы EAV - отстой. Мои предложения по указателю выше помогают , некоторые .

Например, и «order» всегда имеет qty, product_id, line_total; так почему бы не использовать их как настоящие столбцы, если они скрыты в другой таблице, как если бы они были редкими атрибутами? EAV в некоторой степени необходим для магазина, где только некоторые предметы имеют «размер платья», «F-стоп» или «тип передачи». (В этом случае JSON может быть лучшим шаблоном, чем EAV.)

Обзор схемы

Фу, woocommerce хуже чем WP ([ 114] ссылка ):

CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
  meta_id BIGINT UNSIGNED NOT NULL auto_increment,
  order_item_id BIGINT UNSIGNED NOT NULL,
  meta_key varchar(255) default NULL,
  meta_value longtext NULL,
  PRIMARY KEY  (meta_id),
  KEY order_item_id (order_item_id),
  KEY meta_key (meta_key(32))
) $collate;

Индексирование префиксов (meta_key(32)) редко используется и часто приводит к обратным результатам. Тем не менее, вероятно, все мои рекомендации (см. Ссылку выше) применимы, с подходящими изменениями имени.

0
ответ дан Rick James 16 January 2019 в 10:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: