Hi,
I'm wondering how i can improve my queries to make them run better.
I run NEARLY the same query in 3 different places with only small changes, but it still returns all 700+ rows when i may only need 6 and using LIMIT doesn't change anything.
These are my tables:
CREATE TABLE dress_listing (
dress_id int(6) unsigned NOT NULL AUTO_INCREMENT,
member_id int(6) unsigned NOT NULL,
designer_id tinyint(3) unsigned NOT NULL,
condition_id tinyint(1) unsigned NOT NULL,
age_id tinyint(1) unsigned NOT NULL,
shipping_id tinyint(1) unsigned NOT NULL,
terms_id tinyint(1) unsigned NOT NULL,
dress_title varchar(100) NOT NULL,
dress_desc text NOT NULL,
dress_currency char(3) NOT NULL,
dress_price decimal(6,2) NOT NULL,
dress_old_price decimal(6,2) NOT NULL,
price_euro decimal(6,2) unsigned DEFAULT '0.00',
price_obo tinyint(1) unsigned DEFAULT '0',
dress_reduced tinyint(1) unsigned DEFAULT '0',
dress_sku varchar(50) DEFAULT NULL,
dress_tidy_url varchar(90) NOT NULL,
dress_chest double(4,2) NOT NULL DEFAULT '0.00',
dress_waist double(4,2) NOT NULL DEFAULT '0.00',
dress_drop_waist double(4,2) NOT NULL DEFAULT '0.00',
dress_sleeve double(4,2) NOT NULL DEFAULT '0.00',
dress_skirt double(4,2) NOT NULL DEFAULT '0.00',
dress_across_shoulders double(4,2) NOT NULL DEFAULT '0.00',
dress_bodice_shoulder_waist double(4,2) NOT NULL DEFAULT '0.00',
dress_bodice_neck_waist double(4,2) NOT NULL DEFAULT '0.00',
dress_full_length double(4,2) NOT NULL DEFAULT '0.00',
dress_status char(1) NOT NULL DEFAULT 'P',
dress_added datetime NOT NULL,
dress_updated datetime NOT NULL,
dress_reduced_date datetime DEFAULT NULL,
dress_official tinyint(1) unsigned DEFAULT '0',
discount_id varchar(12) DEFAULT NULL,
use_points tinyint(1) unsigned DEFAULT '0',
is_dress tinyint(1) unsigned DEFAULT '1',
PRIMARY KEY (dress_id),
KEY search1 (dress_status,price_euro),
KEY search2 (dress_status,dress_added),
KEY member (member_id,dress_id),
KEY currency (dress_currency)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1738 ;
CREATE TABLE age_ranges (
age_id tinyint(1) unsigned NOT NULL AUTO_INCREMENT,
age_range varchar(6) NOT NULL,
PRIMARY KEY (age_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=8 ;
CREATE TABLE dress_condition (
condition_id tinyint(1) unsigned NOT NULL AUTO_INCREMENT,
dress_condition varchar(10) NOT NULL,
PRIMARY KEY (condition_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=7 ;
CREATE TABLE dress_designers (
designer_id int(3) unsigned NOT NULL AUTO_INCREMENT,
m_id int(4) unsigned DEFAULT '0',
designer_name varchar(30) NOT NULL,
total_dresses int(3) unsigned NOT NULL DEFAULT '0',
designer_link varchar(80) DEFAULT NULL,
designer_show_info tinyint(1) unsigned DEFAULT '0',
designer_tidy_url varchar(50) DEFAULT NULL,
PRIMARY KEY (designer_id),
KEY total_dresses (total_dresses),
KEY designer_name (designer_name(3)),
KEY tot_name (designer_name(4),total_dresses)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=97 ;
CREATE TABLE dress_images (
image_id int(6) unsigned NOT NULL AUTO_INCREMENT,
dress_id int(6) unsigned NOT NULL DEFAULT '0',
image_file varchar(40) NOT NULL,
is_main tinyint(1) unsigned DEFAULT '0',
PRIMARY KEY (image_id),
KEY dress_id (dress_id,is_main)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=5795 ;
CREATE TABLE activity_feed (
activity_id int(10) unsigned NOT NULL AUTO_INCREMENT,
dress_id int(6) NOT NULL,
member_id int(6) NOT NULL,
activity_type tinyint(1) NOT NULL,
activity_date datetime NOT NULL,
PRIMARY KEY (activity_id),
KEY activity_date (activity_date),
KEY dress_id (dress_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1250 ;
CREATE TABLE exchange_rates (
currency char(3) NOT NULL,
rate float unsigned NOT NULL DEFAULT '0',
use char(1) NOT NULL,
symbol char(8) NOT NULL,
updated timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (currency)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE featured_dresses (
featured_id int(4) unsigned NOT NULL AUTO_INCREMENT,
member_id int(6) unsigned DEFAULT NULL,
dress_id int(6) unsigned NOT NULL,
featured_active tinyint(1) unsigned NOT NULL DEFAULT '0',
featured_daily tinyint(1) unsigned DEFAULT '0',
featured_added datetime NOT NULL,
featured_expires date NOT NULL,
PRIMARY KEY (featured_id),
KEY featured_id (featured_id,featured_active),
KEY featured_active (featured_active,featured_expires)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=432 ;
QUERIES
This in on the homepage to show the 8 most recently added, but MYSQL searches all:
SELECT dress_listing.dress_id,
dress_listing.dress_title as listing_title,
dress_listing.dress_reduced,
dress_images.image_file as main_image,
dress_listing.dress_price as price,
exchange_rates.rate,
dress_designers.designer_name,
dress_designers.designer_tidy_url,
dress_listing.dress_tidy_url as listing_tidy_url
FROM dress_listing
LEFT JOIN featured_dresses ON dress_listing.dress_id = featured_dresses.dress_id AND featured_dresses.featured_active = '1'
JOIN exchange_rates ON dress_listing.dress_currency = exchange_rates.currency
JOIN dress_designers ON dress_listing.designer_id = dress_designers.designer_id
LEFT JOIN dress_images ON dress_listing.dress_id = dress_images.dress_id AND is_main = '1'
WHERE dress_listing.dress_status = 'A'
LIMIT 8
My main search page query
SELECT dress_listing.dress_id,
dress_listing.dress_title as listing_title,
dress_images.image_file as main_image,
dress_listing.dress_added,
CASE WHEN featured_dresses.dress_id IS NULL then '0' ELSE '1' END as order_it,
dress_listing.dress_price as price,
dress_listing.dress_old_price as old_price,
dress_listing.price_euro,
dress_listing.price_obo,
exchange_rates.rate,
dress_listing.dress_reduced,
dress_designers.designer_name,
dress_designers.designer_tidy_url,
dress_listing.dress_tidy_url as listing_tidy_url
FROM dress_listing
LEFT JOIN featured_dresses ON dress_listing.dress_id = featured_dresses.dress_id AND featured_dresses.featured_active = '1'
JOIN exchange_rates ON dress_listing.dress_currency = exchange_rates.currency
JOIN dress_designers ON dress_listing.designer_id = dress_designers.designer_id
LEFT JOIN dress_images ON dress_listing.dress_id = dress_images.dress_id AND is_main = '1'
JOIN members_table ON dress_listing.member_id = members_table.member_id
WHERE dress_listing.dress_status = 'A'
AND dress_listing.price_euro between '0' AND '5000'
ORDER BY dress_listing.dress_added DESC
The odd thing is that it uses the index, and avoids full scans and filesort. BUT if i remove the following join it doesnt. Why has this become so important that removing it makes MYSQL use temporary tables and filesort!?
LEFT JOIN featured_dresses ON dress_listing.dress_id = featured_dresses.dress_id AND featured_dresses.featured_active = '1'
Also this is supposed to get the 6 most recent "Activity" rows, but returns 1200+:
SELECT
activity_feed.activity_type,
activity_feed.activity_date,
dress_listing.dress_tidy_url,
dress_listing.dress_id,
dress_listing.dress_title,
dress_listing.dress_price as price,
dress_listing.dress_old_price as old_price,
dress_listing.dress_currency,
exchange_rates.rate,
age_ranges.age_range,
dress_designers.designer_name,
dress_images.image_file
FROM activity_feed
JOIN dress_listing ON activity_feed.dress_id = dress_listing.dress_id
JOIN exchange_rates ON dress_listing.dress_currency = exchange_rates.currency
JOIN dress_designers ON dress_listing.designer_id = dress_designers.designer_id
JOIN age_ranges ON dress_listing.age_id = age_ranges.age_id
LEFT JOIN dress_images ON activity_feed.dress_id = dress_images.dress_id AND is_main = 1
ORDER BY activity_feed.activity_date DESC
LIMIT 6
I removed all currency calculations from the queries and moved them to PHP and to combat the sorting by price added price_euro to the "dress_listing" table which is calculated and inserted when the record is.
Any suggestions for improving these (ESPECIALLY the Activity Feed query) would be greatly appreciated.