views:

866

answers:

2

I have some querys using views, and these run a lot slower than I would expect them to given all relevant tables are indexed (and not that large anyway).

I hope I can explain this:

My main Query looks like this (grossly simplified)

select [stuff] from orders as ord 
left join calc_order_status as ors on (ors.order_id = ord.id)

calc_order_status is a view, defined thusly:

create view calc_order_status as
select ord.id AS order_id,
(sum(itm.items * itm.item_price) + ord.delivery_cost) AS total_total
from orders ord 
left join order_items itm on itm.order_id = ord.id
group by ord.id

Orders (ord) contain orders, order_items contain the individual items associated with each order and their prices.

All tables are properly indexed, BUT the thing runs slowly and when I do a EXPLAIN I get

  # id  select_type  table  type  possible_keys  key  key_len  ref  rows  Extra  
  1 1 PRIMARY ord ALL customer_id NULL NULL NULL 1002 Using temporary; Using filesort 
  2 1 PRIMARY <derived2> ALL NULL NULL NULL NULL 1002   
  3 1 PRIMARY cus eq_ref PRIMARY PRIMARY 4 db135147_2.ord.customer_id 1 Using where 
  4 2 DERIVED ord ALL NULL NULL NULL NULL 1002 Using temporary; Using filesort 
  5 2 DERIVED itm ref order_id order_id 4 db135147_2.ord.id 2

My guess is, "derived2" refers to the view. The individual items (itm) seem to work fine, indexed by order _ id. The problem seems to be Line # 4, which indicates that the system doesn't use a key for the orders table (ord). But in the MAIN query, the order id is already defined: left join calc_order_status as ors on (ors.order _ id = ord.id) and ord.id (both in the main query and within the view) refer to the primary key.

I have read somewhere than MySQL simpliy does not optimize views that well and might not utilize keys under some conditions even when available. This seems to be one of those cases.

I would appreciate any suggestions. Is there a way to force MySQL to realize "it's all simpler than you think, just use the primary key and you'll be fine"? Or are views the wrong way to go about this at all?

A: 

An index is useful for finding a few rows in a big table, but when you query every row, an index just slows things down. So here MySQL probably expects to be using the whole [order] table, so it better not use an index.

You can try if it would be faster by forcing MySQL to use an index:

from orders as ord force index for join (yourindex)
Andomar
Doesn't do the trick...
jms
After rereading the question that makes sense. Step 4 is using a temporary table, and of course an index on [Orders] is not valid for a temporary table. To make use of the index, refactor the query so that it does the join before it starts using temporary tables.
Andomar
+2  A: 

If it is at all possible to remove those joins remove them. Replacing them with subquerys will speed it up a lot.

you could also try running something like this to see if it has any speed difference at all.

select [stuff] from orders as ord 
left join (
  create view calc_order_status as
  select ord.id AS order_id,
  (sum(itm.items * itm.item_price) + ord.delivery_cost) AS total_total
  from orders ord 
  left join order_items itm on itm.order_id = ord.id
  group by ord.id
) as ors on (ors.order_id = ord.id)
corymathews