|
MySQL помогите с запросом | ☑ | ||
---|---|---|---|---|
0
vladnet
29.07.14
✎
19:21
|
Есть запрос который склеивается с таблицей ordered_products:
SELECT products.code, products.name AS products_name, orders.code as order_code, SUM(orders.already_paid) AS already_paid, SUM(products.amount) AS amount, ordered_products.supplier_price AS supplier_price FROM smacs2_production.orders ON checks.id = orders.check_id LEFT JOIN smacs2_production.products ON orders.id = products.order_id LEFT JOIN smacs2_production.ordered_products AS ordered_products ON ordered_products.product_id = products.id Но после того как меняю в нем таблицу ordered_products на внуренний запрос (SELECT ordered_products.vat, ordered_products.product_id, MAX(ordered_products.created_at) AS created_at FROM smacs2_production.ordered_products AS ordered_products GROUP BY ordered_products.product_id) Чтобы исключить дубли, запрос начинает жутко тормозить. Как можно поправить, вообще хотел временную таблицу завести, но нет ее в mysql чтоли и не понятно поможет ли или нет. Причем по отдельности запросы выполняются быстрее намного чем один вместе... Подскажите пожалуйста что можно сделать |
|||
1
kokamoonga
29.07.14
✎
19:26
|
(0) полностью тормозящий запрос как выглядит?
|
|||
2
ДенисЧ
29.07.14
✎
19:27
|
А explain что про него говорит?
|
|||
3
kokamoonga
29.07.14
✎
19:31
|
(0) ну и кстати, довольно оригинальный способ выборки недублирующихся строк. DISTINCT чем не угодил?
|
|||
4
vladnet
29.07.14
✎
19:32
|
(1) Он очень большой
SELECT orders.discount, products.code, products.name AS products_name, orders.code as order_code, orders.delivery_date, products.price*(1-orders.discount/100) AS price, SUM(orders.already_paid) AS already_paid, SUM(orders.shipping_cost) AS shipping_cost, SUM(products.amount) AS amount, SUM(products.delivered_amount) AS delivered_amount, SUM(invoice_positions.total_cost_clean) AS total_cost_clean, SUM(invoice_positions.vat_amount) AS vat_amount, SUM(invoice_positions.amount) AS invoice_amount, ordered_products.vat AS ordered_products_vat, ordered_products.supplier_price AS supplier_price, invoice_positions.vat, invoice_positions.gtd_number, DATE(cashbox_operations.made_at) AS ssss FROM smacs2_production.cashbox_operations LEFT JOIN smacs2_production.checks ON cashbox_operations.id = checks.cashbox_operation_id LEFT JOIN smacs2_production.orders ON checks.id = orders.check_id LEFT JOIN smacs2_production.products ON orders.id = products.order_id LEFT JOIN -- smacs2_production.ordered_products (SELECT ordered_products.vat, ordered_products.supplier_price, ordered_products.product_id, MAX(ordered_products.created_at) AS created_at FROM smacs2_production.ordered_products AS ordered_products GROUP BY ordered_products.product_id) AS ordered_products ON ordered_products.product_id = products.id LEFT JOIN smacs2_production.stock_products ON stock_products.id = products.stock_product_id LEFT JOIN smacs2_production.invoice_positions ON invoice_positions.id = stock_products.id WHERE ((products.workflow_state = 'cancelled' AND cashbox_operations.made_at < products.updated_at) OR products.workflow_state <> 'cancelled') AND cashbox_operations.kind = 'sale' AND ((products.workflow_state = 'cancelled' AND products.is_deleted = 1) OR products.is_deleted <> 1) AND DATE(cashbox_operations.made_at) >= '2014-06-27' AND DATE(cashbox_operations.made_at) < '2014-06-28' AND orders.shipping_id <> 10 AND orders.payment_id = 1 GROUP BY orders.delivery_date, orders.discount, orders.code, products.code, products.name, products.price*(1-orders.discount/100), invoice_positions.vat, invoice_positions.gtd_number ORDER BY orders.delivery_date, orders.code, products.code, ordered_products.created_at DESC |
|||
5
vladnet
29.07.14
✎
19:32
|
(2) еще бы знать что это ( Я больше запросы на 1с пишу
|
|||
6
vladnet
29.07.14
✎
19:34
|
(3) Почитал что советуют, подскажи пожалуйста как им, может distinct быстрее.
вот это надо оптимизировать SELECT ordered_products.vat, ordered_products.product_id, MAX(ordered_products.created_at) AS created_at FROM smacs2_production.ordered_products AS ordered_products GROUP BY ordered_products.product_id Получить надо последний vat который есть в таблице по поле created_at |
|||
7
ДенисЧ
29.07.14
✎
19:34
|
(5) зайди в консоль сервера скажи explain и твой запрос. ; не забудь.
ЧТо получится - покажи. |
|||
8
kokamoonga
29.07.14
✎
19:34
|
(5) вместо GROUP BY id лучше SELECT DISTINCT
группировка на больших таблицах довольно дорогая операция. |
|||
9
vladnet
29.07.14
✎
19:36
|
(8) А можно при этом как то сделать так чтобы брали записи у которых максимальная дата создания?
|
|||
10
kokamoonga
29.07.14
✎
19:38
|
(9) а сейчас берет что попало?
|
|||
11
vladnet
29.07.14
✎
19:39
|
(7) пока сам не разбирался что это
1 PRIMARY orders ref PRIMARY,fk_orders_shippings,fk_orders_payment_ids fk_orders_payment_ids 5 const 249292 Using where; Using temporary; Using filesort 1 PRIMARY checks eq_ref PRIMARY PRIMARY 4 smacs2_production.orders.check_id 1 Using where 1 PRIMARY cashbox_operations eq_ref PRIMARY PRIMARY 4 smacs2_production.checks.cashbox_operation_id 1 Using where 1 PRIMARY products ref fk_products_orders,index_products_on_workflow_state,index_products_on_updated_at,updated_at fk_products_orders 4 smacs2_production.orders.id 1 Using where 1 PRIMARY <derived2> ALL (null) (null) (null) (null) 1297947 1 PRIMARY stock_products eq_ref PRIMARY PRIMARY 4 smacs2_production.products.stock_product_id 1 Using index 1 PRIMARY invoice_positions eq_ref PRIMARY PRIMARY 4 smacs2_production.stock_products.id 1 2 DERIVED ordered_products index (null) fk_ordered_products_products 5 (null) 1758871 |
|||
12
vladnet
29.07.14
✎
19:41
|
(10) сейчас то правильно берет
например в таблице есть записи 2014.01.04 молоко 12 2014.02.04 молоко 11 2014.03.04 молоко 10 2014.03.04 колбаса 11 нужно чтобы вернуло 2014.03.04 молоко 10 2014.03.04 колбаса 11 т.е. последние поставки по каждому товару |
|||
13
ДенисЧ
29.07.14
✎
19:41
|
(11) В индексы не попадает.
|
|||
14
vladnet
29.07.14
✎
19:49
|
(13) А как добавить индексы. И можно ли добавить их временные? База не моя. И по каким полям добавить?
|
|||
15
kokamoonga
29.07.14
✎
19:59
|
(0) >>> вообще хотел временную таблицу завести, но нет ее в mysql
Прямо-таки и нет?.. http://dev.mysql.com/doc/refman/5.6/en/create-table.html Может помочь, если этот подзапрос с группировкой вынести во временную |
|||
16
kokamoonga
29.07.14
✎
20:00
|
(15) + это конечно если у юзера есть права на CREATE/DROP
|
|||
17
vladnet
29.07.14
✎
20:01
|
Может пример дашь простой?
В 1с это просто говоришь INTO ИмяВременнойТаблицы |
|||
18
kokamoonga
29.07.14
✎
20:05
|
(17) там же в доке куча примеров, типа такого
CREATE TEMPORARY TABLE IF NOT EXISTS `schema`.`Employee` ( `idEmployee` VARCHAR(45) NOT NULL , `Name` VARCHAR(255) NULL , `idAddresses` VARCHAR(45) NULL , PRIMARY KEY (`idEmployee`) , CONSTRAINT `fkEmployee_Addresses` FOREIGN KEY `fkEmployee_Addresses` (`idAddresses`) REFERENCES `schema`.`Addresses` (`idAddresses`) ON DELETE NO ACTION ON UPDATE NO ACTION) ENGINE = InnoDB DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin |
|||
19
vladnet
29.07.14
✎
20:08
|
Да есть, но не понятно как это всунуть в запрос. Чтобы в запросе было:
1. создание временной таблицы 2. помещение во временную таблицу подзапроса 3. выполнение основного запроса 4. грохнуть временную таблицу? |
|||
20
kokamoonga
29.07.14
✎
20:13
|
(19) 1. Создание в (18). С поправкой на нужные поля. Очевидно они должны совпадать с твоей будущей выборкой.
2. Помещение подзапроса типа так: INSERT INTO `temporary_table` VAlUES (val1, val2,...valN) SELECT val1, val2,...,valN FROM `ordered_products` WHERE clause 3. Выполнение основного запроса с заменой подзапроса на : SELECT * FROM temporary_table 4. DROP temporary_table (http://dev.mysql.com/doc/refman/5.1/en/drop-table.html) |
|||
21
kokamoonga
29.07.14
✎
20:14
|
(20) + даже если не поможет, увлекательно проведешь время за чтением документации:)
|
|||
22
vladnet
29.07.14
✎
20:15
|
(21) Ага )) Спасибо, надеюсь как нибудь решим. Но насколько понял тут индексы надо добавлять.
|
|||
23
kokamoonga
29.07.14
✎
20:17
|
(22) тут надо от запросов-монстров избавляться. когда таблицы распухнут до серьезных размеров, с такими запросами никакие временные таблицы не помогут.
|
|||
24
Fragster
гуру
29.07.14
✎
20:18
|
еще неплохо бы описать, что автор хочет получить своим запросом (возможно можно просто пересмотреть его логику)
|
|||
25
kokamoonga
29.07.14
✎
20:19
|
(24) ну собственно я об этом в (23).
Часть логики запроса, как мне кажется, может без напряжения переехать в основной код. А другую часть можно переписать как-то попроще. |
|||
26
vlandev
29.07.14
✎
20:59
|
Специально удалять временную таблицу не обязательно:
A TEMPORARY table is visible only to the current session, and is dropped automatically when the session is closed Хотя это зависит от особенностей подключения к MySQL. |
|||
27
kokamoonga
29.07.14
✎
22:23
|
(26) Лучше перебдеть чем недобдеть.
|
|||
28
vladnet
30.07.14
✎
10:27
|
Запрос очень простой, есть заказ, у заказа есть табличная часть. Нужно получить все заказанные товары и присоединить к ним последнюю цену из поставок этого товара нам.
Ничего серьезного по моему в запросе нет. Проблема в том что запросы по отдельности выполняются быстро. А как только их склеиваю получается очень долго. На 1с у меня никогда таких проблем не было. |
|||
29
rsv
30.07.14
✎
10:42
|
(28) Делайте джойны последовательно , а не все сразу. Обнаружите узкое место .
|
|||
30
rsv
30.07.14
✎
10:44
|
Возможно в join придется добавить пару условий соединения и так далее или еще чего ...
|
|||
31
rsv
30.07.14
✎
10:45
|
Имхо вся литература по mySQL по вывод - Хорош на коротких простых запросах к нормализованным таблицам.
|
|||
32
Fragster
гуру
30.07.14
✎
11:26
|
(29) у него в explain всё написано, каких индексов не хватает и т.п. вопрос в том, правильна ли сама логика запроса
|
|||
33
Fragster
гуру
30.07.14
✎
11:27
|
(28) дай доступ к phpmyadmin
|
|||
34
vladnet
30.07.14
✎
11:32
|
(33) К сожалению там не вебка (
Затык появляется после того как я меняю LEFT JOIN smacs2_production.ordered_products AS ordered_products На LEFT JOIN (SELECT ordered_products.vat, ordered_products.product_id, MAX(ordered_products.created_at) AS created_at FROM smacs2_production.ordered_products AS ordered_products GROUP BY ordered_products.product_id) AS ordered_products Причем если по отдельности выполнять то все хорошо работает |
|||
35
vladnet
30.07.14
✎
11:33
|
(33) Могу через Амми админ доступ дать посмотреть все. В скайпе: miragevlad
|
|||
36
vladnet
30.07.14
✎
11:34
|
Через временные таблицы кстати пока не получается, у меня нет доступа создавать таблицы, по крайней мере пока ((
|
|||
37
Fragster
гуру
30.07.14
✎
11:41
|
(35) есть тимвьювер и почта в личке
|
|||
38
vladnet
30.07.14
✎
11:52
|
(37) написал
|
|||
39
kokamoonga
30.07.14
✎
14:02
|
(28) никто и не говорил, что запрос сложный. Просто в нем 4 джонйна на больших (потенциально больших) таблицах. Плюсом к этом подзапрос, который вообще-то не нужен. Поля выборки, условия и группировку можно вынести в общие группы.
|
|||
40
kokamoonga
30.07.14
✎
15:24
|
соорудил нечто похожее по смыслу на реальных данных.
Два запроса: SELECT customers.customerID, customers.Login, customers.Email, orders.orderID, MAX(orders.order_amount) AS order_amount FROM orders INNER JOIN customers ON orders.customerID = customers.customerID WHERE orders.order_amount > 1000 GROUP BY orders.customerID ORDER BY orders.customerID SELECT customers.customerID, customers.Login, customers.Email, Sub.orderID, MAX(Sub.order_amount) AS order_amount FROM (SELECT orders.orderID, orders.order_amount, orders.customerID FROM orders WHERE orders.order_amount > 1000 ) Sub LEFT OUTER JOIN customers ON Sub.customerID = customers.customerID GROUP BY Sub.customerID ORDER BY customers.customerID Вариант с простым джойном без подзапроса стабильно быстрее процента на 2,5-3. Может это погрешность, но выглядит логично. |
|||
41
kokamoonga
30.07.14
✎
15:25
|
(40) + в первом варианте не INNER, а LEFT JOIN
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |