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.