2010-06-28 2 views
5

Следующий запрос работает, но очень медленный для 10 записей (2 секунды). Профилирование говорит о создании таблицы tmp, но я не уверен, почему.MySQL. Как оптимизировать этот запрос?

В основном, я присоединяюсь к текущему пользователю, к группам acl, чтобы получить все группы, в которых они находятся, затем присоединяется к группам к компаниям, чтобы получить все компании, в которых они находятся, а затем присоединяется к компаниям к заказам , чтобы получить все заказы ..

Если удалить эту строку

ORDER BY orders.created_on DESC 

то запрос выполняется в 0,06 секунды (более приемлемо) ..

Помощь, любые идеи о том, как оптимизировать ? Большое спасибо :)

SELECT 
    orders.uuid, 
    companies.name as company_name 
FROM 
    users u 
JOIN  
    users_acl_groups g on u.uuid = g.user_uuid 
JOIN 
    users_acl acl on (acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid) 
JOIN 
    companies on acl.item_uuid = companies.uuid 
JOIN 
    orders on companies.uuid = orders.company_uuid 
WHERE 
    u.uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and orders.status <> '' 
ORDER BY orders.created_on DESC 

limit 0, 10; 

UPDATE, то объяснить запроса ..

1 ПРОСТЫЕ заказы ALL 9403 Использование временно; Использование filesort

1 SIMPLE acl ALL 1859 Использование; Использование буфера объединения

1 ПРОСТОЙ g ВСЕ 2005 Использование где; Использование присоединиться к буферу

1 ПРОСТЫЕ компании eq_ref ОСНОВНОЙ Primary 52 table.orders.company_uuid 1

1 SIMPLE у ВСЕХ 33595 Использование где; Отличный; Использование буфера присоединиться

+0

Изменен ваш заголовок, поскольку угадывает, что он стоил вам нисходящего потока из-за его императивного и требовательного тона, когда ваш вопрос сформулирован красиво. –

+0

Попробуйте использовать тот же запрос с соединением, который применяется в любом столбце, отличном от UID. Попробуйте сделать это с помощью int, float, string, UID и обратите внимание на время. Давайте также знать, если вы найдете какие-либо изменения. –

+0

У вас есть указатель на orders.created_on? Покажите результат на 'EXPLAIN' по вашему запросу. Возможно, вы могли бы воспользоваться другими индексами. Какой 'EXPLAIN' скажет нам. – nos

ответ

2

Рассматривали ли вы сделать таблица фактов дизайн в стиле, как шаг денормализации?

В основном это своего рода многие-ко-многим таблице пересечений, например:

CREATE TABLE user_order_fact (
    user_uuid ... 
    order_uuid ... 
    order_created_on ... 
    order_status ... 
    company_name ..., 
    primary key (user_uuid, order_uuid), 
    key (user_uuid, order_status, order_created_on, order_uuid, company_name) 
); 

... fill with data ... 

SELECT 
    order_uuid, 
    company_name 
FROM 
    user_order_fact 
WHERE 
    user_uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and order_status <> '' 
ORDER BY order_created_on DESC 

limit 0, 10; 

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

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

+0

Хмм, может быть, ПК просто order_uid. Я не гарантирую, что это лучший дизайн, просто пытаясь дать вам представление о том, что я имею в виду. –

0

убедитесь, что «orders.created_on» имеет индекс ... Если это так, то подход Билла наверху будет лучшим, но для этого потребуется немного работы.

+0

Я так думаю? KEY 'created_on' (' created_on') – Brett

0

Трудно ответить, не зная о существующих индексах или объеме каждой таблицы.

Кроме того, без подробной информации о модели ... запрос возвращает все результаты?

Включены ли все пользователи в группу? Кажется, что не ... и запрос не будет возвращать пользователей за пределами группы.

Может ли группа принадлежать группе, призывая к рекурсивному запросу?

+0

Я пытался работать с этим рекурсивным вопросом запроса, но мне не повезло :(таблица тихая, всего 10 000 записей. На данный момент индексов нет. – Brett

+0

@Brett: индексы, если они присутствуют в этом случае, не будут работать, так как оператор NOT и оператор Like не используют индексы –

0

Я не уверен, что может быть точной причиной для его принятия 2 сек. Но это не возможно для этого запроса Fetching 10 записей, но то, что видите здесь

  1. acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid

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

  2. ORDER BY orders.created_on. Использование Order by на date было бы не таким оптимальным, как использование PK или любое целочисленное значение. более подходит.

  3. orders.status <> '' При использовании каких-либо индексов в таблицах, то никаких индексов не могут быть использованы в этом запросе, поскольку НЕ Оператор и Как Оператор не использует индексы при использовании в любом запросе.

  4. Объем записей, представленных в таблице, может быть другой причиной, но только из-за вышеперечисленных факторов. В противном случае он мог бы обрабатывать большой объем.

основным фактором, который я думаю, что это UID используется в Присоединяется Таким образом, все три избегая условия можно увидеть в запросе, что может сделать ваш запрос ленивые

+0

Привет, спасибо за ваши ответы .. Что такое минимизация в no.2? – Brett

0

Несколько идей:

Фактически вы не выбираете orders.created_on в своем запросе. Поэтому нет смысла сортировать по этой колонке. Может быть, выбирая его (SELECT orders.created_on ...), вы поможете производительности (просто дикая догадка - я понятия не имею, что я здесь говорю).

Вы всегда можете сортировать в своем приложении - если у вас нет большого количества записей, возвращаемых вашим запросом.

Иногда бывает более разумным использовать N небольших запросов вместо 1 большого sql-запроса. Псевдокод:

user_id = get_one("SELECT uuid FROM users WHERE ..."); 
group_ids = get_many("SELECT uuid FROM groups WHERE user_uuid = " + user_id); 
comps_ids = get_many("SELECT DISTINCT item_uuid FROM acls WHERE user_uuid = " + user_id + " OR group_uuid IN " + groups_ids.to_q()); 
orders = get_many("SELECT * FROM orders WHERE company_uuid IN " + comps_ids.as_q() + " WHERE status <> '' ORDER BY created_on"); 

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

  • Нет связанных вопросов^_^