MySql медленно выбирает из подзапроса (хотя сам подзапрос быстрый) - PullRequest
1 голос
/ 28 марта 2011

Я пытаюсь ускорить этот запрос:

SELECT order.id
    FROM (
     SELECT o.id 
     FROM `order` as `o` 
     INNER JOIN order_item as oi on
        oi.order_id = o.id
        AND `o`.`canceled` = 0
        AND ( `o`.`return_date` > "2011-03-14" OR oi.checked = 0 OR '2011-03-14' < oi.last_update)
    ) as `order`

Время составляет 0,0930 секунды. Подзапрос (SELECT * FROM order as o ...) на собственные часы за 0,0005 секунд. Таблица, в которой я тестирую, содержит около 10000 строк, 43 строки возвращаются из подзапроса where-clause.

Кроме ускорения запроса, мне бы очень хотелось, чтобы кто-нибудь объяснил мне, почему запрос становится более чем в 100 раз медленнее, когда я заключаю его в другой запрос?

MySql объяснил мне, что подзапрос сам выбирает сначала o, а затем oi. MySql объяснение для всего запроса сначала выбирает (что является производным 2?), Затем o и oi в этом порядке.

Я бы хотел, чтобы подзапрос был подзапросом, потому что я делаю много соединений, которых нет в предложении where (которое я исключил из кода и тестов). Если бы я использовал подзапрос самостоятельно, с соединениями, запрос был бы еще медленнее.

Любая помощь будет высоко ценится. Я искал ответы, но не могу их найти, и это может быть просто потому, что я не знаю, что искать, если да, то я прошу прощения.

Ответы [ 2 ]

1 голос
/ 28 марта 2011

MySQL буферизует встроенное представление перед выполнением каких-либо операций с ним.

0.0006 секунд, которые вы видите для первого запроса - это, скорее всего, время ответа (извлечена первая строка), а не общее время (извлечена последняя строка).

Если id - это PRIMARY KEY на вашем order столе, вам не нужно GROUP BY на нем.

Если у вас много товаров в заказе (в среднем более 20 товаров в заказе), вы можете попробовать создать следующие индексы:

order_item (order_id, checked)
order_item (order_id, last_update)

и разбиение вашего коррелированного подзапроса на две части:

SELECT  *
FROM    order o
WHERE   o.canceled = 0
        AND
        (
        o.return_date > '2011-03-14'
        OR
        (
        SELECT  MIN(checked)
        FROM    order_item oi
        WHERE   order_id = o.id
        ) = 0
        OR
        (
        SELECT  MAX(last_update)
        FROM    order_item oi
        WHERE   oi.order_id = o.id
        ) > '2011-03-14'
        )

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

0 голосов
/ 28 марта 2011
  1. проверка индексов
  2. оптимизировали ли вы таблицы, с которыми работаете?
  3. запрос будет работать быстрее, если вы измените «*» в операторе SELECT на фактические именастолбцы, которые вам нужны.
  4. вам нужно несколько GROUP BY "идентификатор заказа" - один внутри другого?
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...