Leave a Comment
SQL. Как переписать correlation subquery в JOIN to derived table
Допустим есть такая таблица
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
CREATE TABLE `payment` ( `payment_id` smallint(5) unsigned NOT NULL auto_increment, `customer_id` smallint(5) unsigned NOT NULL, `staff_id` tinyint(3) unsigned NOT NULL, `rental_id` int(11) default NULL, `amount` decimal(5,2) NOT NULL, `payment_date` datetime NOT NULL, `last_update` timestamp NOT NULL ... on update CURRENT_TIMESTAMP, PRIMARY KEY (`payment_id`), KEY `idx_fk_staff_id` (`staff_id`), KEY `idx_fk_customer_id` (`customer_id`), KEY `fk_payment_rental` (`rental_id`), CONSTRAINT `fk_payment_rental` FOREIGN KEY (`rental_id`) REFERENCES `rental` (`rental_id`), CONSTRAINT `fk_payment_customer` FOREIGN KEY (`customer_id`) REFERENCES `customer` (`customer_id`) , CONSTRAINT `fk_payment_staff` FOREIGN KEY (`staff_id`) REFERENCES `staff` (`staff_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
И нам нужно для каждого покупателя вернуть данные его последнего заказа.
Так делать очень плохо (DEPENDENT SUBQUERY, делает очень много запросов за строками):
1 2 3 4 5 6 7 8 |
EXPLAIN SELECT p.* FROM payment p WHERE p.payment_date = ( SELECT MAX(payment_date) FROM payment WHERE customer_id=p.customer_id ) |
Делать надо так:
1 2 3 4 5 6 7 8 9 10 |
EXPLAIN SELECT p.* FROM ( SELECT customer_id, MAX(payment_date) as last_order FROM payment GROUP BY customer_id ) AS last_orders INNER JOIN payment p ON p.customer_id = last_orders.customer_id AND p.payment_date = last_orders.last_order |
Тогда запросов будет всего два.
Jay Pipes, «SQL Query Tuning: The Legend of Drunken Query Master», слайды 56-59.(http://www.slideshare.net/ZendCon/sql-query-tuning-the-legend-of-drunken-query-master-presentation)
Similar Posts
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.