MySQL join with Direct table or subfields of table - mysql

First query:
SELECT
u.id,
u.first_name,
u.last_name,
u.tazkera_id,
cu.relation_type,
CASE csp.`shift`
WHEN '1' THEN 'Morning'
WHEN '2' THEN 'Afternoon'
else 'Neither'
END AS shift
FROM `course_user` as cu
LEFT JOIN `courses` as c ON c.id = cu.`course_id`
LEFT JOIN (
select users.id,
users.first_name,
users.last_name,
users.tazkera_id
FROM `users`
) as u ON u.id = cu.`user_id`
left JOIN `course_schedule_prefs` as csp ON csp.`user_id` = cu.`user_id`
Where cu.relation_type = 1 group by cu.`user_id`;
Second Query:
SELECT
u.id,
u.first_name,
u.last_name,
u.tazkera_id,
cu.relation_type,
CASE csp.`shift`
WHEN '1' THEN 'Morning'
WHEN '2' THEN 'Afternoon'
else 'Neither'
END AS shift
FROM `course_user` as cu
LEFT JOIN `courses` as c ON c.id = cu.`course_id`
LEFT JOIN users as u ON u.id = cu.`user_id`
left JOIN `course_schedule_prefs` as csp ON csp.`user_id` = cu.`user_id`
Where cu.relation_type = 1 group by cu.`user_id`;
Tables :
users:
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`first_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`is_password_reset` int(11) NOT NULL DEFAULT '0',
`login_ip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`login_date` datetime DEFAULT NULL,
`last_login_ip` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`last_login_date` datetime DEFAULT NULL,
`is_email_address_verified` int(11) NOT NULL DEFAULT '0',
`failed_login_attempts` int(11) DEFAULT NULL,
`last_failed_login_date` datetime DEFAULT NULL,
`tazkera_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`province_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`district_code` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`village` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`home_address` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`promote_unique_user_id` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`forgot_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
`email_confirm_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`district_other` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`father_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`training_provider_id` int(10) unsigned DEFAULT NULL,
`is_profile_completed` int(11) DEFAULT NULL,
`active` int(11) DEFAULT '1',
`picture` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`small_picture` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`last_poll` bigint(20) DEFAULT NULL,
`last_password_reset` date DEFAULT NULL,
`presence_status` int(11) DEFAULT NULL,
`auto_presence` int(11) NOT NULL DEFAULT '0',
`last_activity` timestamp NULL DEFAULT NULL,
`trash` tinyint(4) NOT NULL DEFAULT '0',
`login_approval` tinyint(4) NOT NULL DEFAULT '0',
`lang` varchar(2) COLLATE utf8_unicode_ci NOT NULL DEFAULT 'en',
`cover` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`small_cover` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`forum_reputation` int(11) NOT NULL DEFAULT '0',
`forum_suspension_date` date DEFAULT NULL,
`forum_status` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `users_email_unique` (`email`),
KEY `users_training_provider_id_foreign` (`training_provider_id`),
CONSTRAINT `users_training_provider_id_foreign` FOREIGN KEY (`training_provider_id`) REFERENCES `training_providers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1000038 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
course_users:
CREATE TABLE `course_user` (
`course_id` int(10) unsigned DEFAULT NULL,
`user_id` int(10) unsigned DEFAULT NULL,
`relation_type` int(11) DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
KEY `course_user_course_id_foreign` (`course_id`),
KEY `course_user_user_id_foreign` (`user_id`),
CONSTRAINT `course_user_course_id_foreign` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `course_user_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
courses;
CREATE TABLE `courses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`curriculum_id` int(10) unsigned DEFAULT NULL,
`training_center_id` int(10) unsigned DEFAULT NULL,
`training_coordinator_id` int(10) unsigned DEFAULT NULL,
`focal_point_id` int(10) unsigned DEFAULT NULL,
`start_date` date DEFAULT NULL,
`end_date` date DEFAULT NULL,
`start_time` time DEFAULT NULL,
`end_time` time DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`shift` int(11) DEFAULT NULL,
`stage_id` int(10) unsigned DEFAULT NULL,
`stream_id` int(10) unsigned DEFAULT NULL,
`unit_id` int(10) unsigned DEFAULT NULL,
`master_trainer_id` int(10) unsigned DEFAULT NULL,
`status` int(11) DEFAULT NULL,
`pre_test_generated` int(11) NOT NULL DEFAULT '0',
`post_test_generated` int(11) NOT NULL DEFAULT '0',
`conduct_days` int(11) DEFAULT NULL,
`no` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`evaluation_available` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `courses_curriculum_id_foreign` (`curriculum_id`),
KEY `courses_training_coordinator_id_foreign` (`training_coordinator_id`),
KEY `courses_focal_point_id_foreign` (`focal_point_id`),
KEY `courses_stage_id_foreign` (`stage_id`),
KEY `courses_stream_id_foreign` (`stream_id`),
KEY `courses_unit_id_foreign` (`unit_id`),
KEY `courses_master_trainer_id_foreign` (`master_trainer_id`),
KEY `courses_training_center_id_foreign` (`training_center_id`),
CONSTRAINT `courses_curriculum_id_foreign` FOREIGN KEY (`curriculum_id`) REFERENCES `curriculums` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_focal_point_id_foreign` FOREIGN KEY (`focal_point_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_master_trainer_id_foreign` FOREIGN KEY (`master_trainer_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_stage_id_foreign` FOREIGN KEY (`stage_id`) REFERENCES `stages` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_stream_id_foreign` FOREIGN KEY (`stream_id`) REFERENCES `streams` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_training_center_id_foreign` FOREIGN KEY (`training_center_id`) REFERENCES `training_centers` (`id`),
CONSTRAINT `courses_training_coordinator_id_foreign` FOREIGN KEY (`training_coordinator_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `courses_unit_id_foreign` FOREIGN KEY (`unit_id`) REFERENCES `units` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=139 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
course_schedule_prefs;
CREATE TABLE `course_schedule_prefs` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cunduct_days` int(11) DEFAULT NULL,
`training_centers` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`shift` int(11) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_id` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `course_schedule_prefs_user_id_foreign` (`user_id`),
CONSTRAINT `course_schedule_prefs_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
My question is , which one of this query is good in term of performance and accuracy. Why ?
first query: I join directly with table; select all columns of table.
Second query: I used subquery inside of join; select only those element which I need it.
Note : My main question is about users table which is in join

There are too many possibilities here. There is no simple, 'straight', answer.
With LEFT JOIN (instead of JOIN), the Optimizer cannot start with the subquery, which it would usually like to do.
If there is a WHERE clause and it is useful for filtering rows, the Optimizer would like to start with the table that is filtered the most. Your WHERE clause smells like a flag, which is usually not very useful.
If a subquery has a GROUP BY or LIMIT, then it may significantly shrink the number of rows to work with. (Not in your case.) This might make the subquery approach better.
If cu has INDEX(relation_type, user_id), the Optimizer may decide that handling all of the WHERE and GROUP BY leads to the best bet, thereby starting with cu as the 'first' table.
In old versions of MySQL, subqueries in JOIN ( SELECT ... ) had no way of getting an index, thereby leading to inefficient table scans of that tmp table. In new versions (starting with 5.6, I think), the Optimizer takes the extra step (which costs something) to generate the optimal index ((id) in this case) after creating the tmp table and before JOINing it.
More
2 more table definitions needed.
Do you have the indexes I suggested?
InnoDB really needs a PRIMARY KEY - See many:many for advice on course_user.

Related

Indexing query on large datasets

I have a basic query that runs great on small datasets but when you hit 100,000 results, the query takes forever (1.9 seconds) to run. Please help with possible indexing because maybe I missed something (have already indexed quite extensively). Below is the query
SELECT
count( * ) AS counts
FROM
pages pg
INNER JOIN products AS p
ON p.page_id = pg.id
INNER JOIN pages_description AS pgd
ON pg.id = pgd.page_id
and pgd.language_id = 1
WHERE
pgd.active = 1
AND pgd.deleted = 0
AND pg.type = 4
AND pg.created_date between '2018-01-30 06:00:00' and '2018-12-30 09:00:00'
AND pg.modified_date between '2018-01-30 07:00:00' and '2018-12-30 09:00:00'
CREATE TABLE `pages` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`parent` int(11) DEFAULT NULL,
`type` int(11) DEFAULT NULL,
`template_id` int(11) DEFAULT NULL,
`link` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`local_left` tinyint(1) DEFAULT NULL,
`sort_order` int(11) DEFAULT NULL,
`faceted_search` tinyint(1) DEFAULT NULL,
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`modified_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_parent` (`parent`) USING BTREE,
KEY `idx_type` (`type`) USING BTREE,
KEY `idx_template` (`template_id`) USING BTREE,
KEY `idx_local_left` (`local_left`) USING BTREE,
KEY `idx_sort` (`sort_order`) USING BTREE,
KEY `idx_faceted_search` (`faceted_search`) USING BTREE,
KEY `idx_dates` (`type`,`created_date`,`modified_date`,`id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=149352 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `pages_description` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`page_id` int(11) NOT NULL,
`language_id` int(11) NOT NULL DEFAULT '1',
`name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`menu_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`content` text COLLATE utf8_unicode_ci,
`sub_content` text COLLATE utf8_unicode_ci,
`seo_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`h1` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`keywords` text COLLATE utf8_unicode_ci,
`title_tag` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`meta_description` varchar(390) COLLATE utf8_unicode_ci DEFAULT NULL,
`canonical_tag` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`active` tinyint(1) DEFAULT NULL,
`deleted` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `unq_page_lang` (`page_id`,`language_id`) USING BTREE,
KEY `idx_name` (`name`) USING BTREE,
KEY `idx_menu_name` (`menu_name`) USING BTREE,
KEY `idx_active` (`active`) USING BTREE,
KEY `idx_deleted` (`deleted`) USING BTREE,
KEY `idx_lang` (`language_id`),
KEY `idx_page` (`page_id`) USING BTREE,
KEY `idx_active_deleted_id` (`active`,`deleted`,`page_id`,`language_id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=149319 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`page_id` int(11) NOT NULL,
`on_hand` int(11) NOT NULL DEFAULT '0',
`buy` tinyint(1) NOT NULL DEFAULT '0',
`rfq` tinyint(1) NOT NULL DEFAULT '1',
`model` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`parent_type` int(11) NOT NULL DEFAULT '1',
`image` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_alt` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`image_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`base_price` decimal(10,2) DEFAULT NULL,
`length` decimal(10,5) DEFAULT NULL,
`width` decimal(10,5) DEFAULT NULL,
`height` decimal(10,5) DEFAULT NULL,
`weight` decimal(10,5) DEFAULT NULL,
`tax_class` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`ready_to_ship` tinyint(1) DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `unq_page_id` (`page_id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=148391 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
I know one might think that 1.9 seconds is forever but this is a web app and needs to be responsive. I have added the schema for the tables in question.
I was able to figure it out. I can't believe I missed this. I optimized the tables and the query was then cut down to 350ms.

MySQL - Why can't I add a foreign key here?

I'm not sure why I'm not able to add a particular foreign key here. These tables were generated via MySQL Workbench, and based on the MySQL documentation and on searching for other similar problems / solutions, I think everything is in order...yet I can't add one foreign key in particular:
inspection_statuses.inspection_id needs to reference inspection_responses.tpa_result
What am I missing / overlooking?
This is the statement I'm trying to use to add the new foreign key:
ALTER TABLE `vipsouth_app`.`inspection_statuses`
ADD CONSTRAINT `inspection_statuses_ibfk_3`
FOREIGN KEY (`inspection_id`)
REFERENCES `vipsouth_app`.`inspection_responses` (`tpa_result`)
ON DELETE NO ACTION
ON UPDATE NO ACTION;
And that produces this error:
Operation failed: There was an error while applying the SQL script to the database.
ERROR 1005: Can't create table vipsouth_app.#sql-1f48_7 (errno: 150 "Foreign key constraint is incorrectly formed")
CREATE TABLE `inspection_responses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inspection_request_id` int(10) unsigned NOT NULL,
`tpa_result` varchar(10) CHARACTER SET utf8 NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` int(10) unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL,
`updated_by` int(10) unsigned DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`deleted_by` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
UNIQUE KEY `tpa_result_UNIQUE` (`tpa_result`),
KEY `inspection_responses_ibfk_1_idx` (`inspection_request_id`),
CONSTRAINT `inspection_responses_ibfk_1` FOREIGN KEY (`inspection_request_id`) REFERENCES `inspection_requests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `inspection_statuses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inspection_request_id` int(10) unsigned NOT NULL,
`inspection_response_id` int(10) unsigned NOT NULL,
`tpa_code` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`inspection_id` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
`status` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`note` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL,
`url` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` int(10) unsigned NOT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`updated_by` int(10) unsigned DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`deleted_by` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `inspection_statuses_ibfk_1_idx` (`inspection_request_id`),
KEY `inspection_statuses_ibfk_2_idx` (`inspection_response_id`),
CONSTRAINT `inspection_statuses_ibfk_1` FOREIGN KEY (`inspection_request_id`) REFERENCES `inspection_requests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `inspection_statuses_ibfk_2` FOREIGN KEY (`inspection_response_id`) REFERENCES `inspection_responses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
The data types and constraints defined on both the columns should be exactly the same. Except for a foreign key can be NULLable.
This should do it for you. I did not get any error.
SET foreign_key_checks = 0;
CREATE TABLE `inspection_responses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inspection_request_id` int(10) unsigned NOT NULL,
`tpa_result` varchar(10) CHARACTER SET utf8 NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` int(10) unsigned NOT NULL DEFAULT '0',
`updated_at` timestamp NULL DEFAULT NULL,
`updated_by` int(10) unsigned DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`deleted_by` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
UNIQUE KEY `tpa_result_UNIQUE` (`tpa_result`),
KEY `inspection_responses_ibfk_1_idx` (`inspection_request_id`),
CONSTRAINT `inspection_responses_ibfk_1` FOREIGN KEY (`inspection_request_id`) REFERENCES `inspection_requests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE `inspection_statuses` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`inspection_request_id` int(10) unsigned NOT NULL,
`inspection_response_id` int(10) unsigned NOT NULL,
`tpa_code` varchar(4) COLLATE utf8_unicode_ci NOT NULL,
`user_id` varchar(30) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`inspection_id` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
`status` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL,
`note` varchar(1000) COLLATE utf8_unicode_ci DEFAULT NULL,
`url` varchar(1024) COLLATE utf8_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` int(10) unsigned NOT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`updated_by` int(10) unsigned DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
`deleted_by` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `id_UNIQUE` (`id`),
KEY `inspection_statuses_ibfk_1_idx` (`inspection_request_id`),
KEY `inspection_statuses_ibfk_2_idx` (`inspection_response_id`),
CONSTRAINT `inspection_statuses_ibfk_1` FOREIGN KEY (`inspection_request_id`) REFERENCES `inspection_requests` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `inspection_statuses_ibfk_2` FOREIGN KEY (`inspection_response_id`) REFERENCES `inspection_responses` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
SET foreign_key_checks = 1;

Foreign ID in SQL tables to link one table to another

This is my SQL code which links users to items based on tutorials:
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`user_password_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`user_email` varchar(254) COLLATE utf8_unicode_ci NOT NULL,
`user_access_level` tinyint(3) unsigned NOT NULL DEFAULT '0',
`user_active` tinyint(1) NOT NULL DEFAULT '0',
`user_activation_hash` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`user_password_reset_hash` char(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`user_password_reset_timestamp` bigint(20) DEFAULT NULL,
`user_failed_logins` tinyint(1) NOT NULL DEFAULT '0',
`user_last_failed_login` int(10) DEFAULT NULL,
`user_registration_datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_registration_ip` varchar(39) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0.0.0.0',
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name` (`user_name`),
UNIQUE KEY `user_email` (`user_email`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `item` (
`item_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`item_title` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_location` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_description` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`item_status` int(1) unsigned NOT NULL,
PRIMARY KEY (`item_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
http://sqlfiddle.com/#!9/fd011
I'm getting a bit confused about how to link the items to the user. It seems like I need something called a foreign key on the items, a bit like this in my item table:
FOREIGN KEY (user_id) REFERENCES user(ID)
I can't seem to get it to compile and query successfully. Can anyone please show me the right way to associate the items with the user.
You need to add the user_id column to the items table along with the constraint:
CREATE TABLE IF NOT EXISTS `users` (
`user_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_name` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`user_password_hash` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`user_email` varchar(254) COLLATE utf8_unicode_ci NOT NULL,
`user_access_level` tinyint(3) unsigned NOT NULL DEFAULT '0',
`user_active` tinyint(1) NOT NULL DEFAULT '0',
`user_activation_hash` varchar(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`user_password_reset_hash` char(40) COLLATE utf8_unicode_ci DEFAULT NULL,
`user_password_reset_timestamp` bigint(20) DEFAULT NULL,
`user_failed_logins` tinyint(1) NOT NULL DEFAULT '0',
`user_last_failed_login` int(10) DEFAULT NULL,
`user_registration_datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`user_registration_ip` varchar(39) COLLATE utf8_unicode_ci NOT NULL DEFAULT '0.0.0.0',
PRIMARY KEY (`user_id`),
UNIQUE KEY `user_name` (`user_name`),
UNIQUE KEY `user_email` (`user_email`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
CREATE TABLE IF NOT EXISTS `item` (
`item_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
user_id int unsigned,
`item_title` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_location` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_description` varchar(64) COLLATE utf8_unicode_ci NOT NULL,
`item_datetime` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`item_status` int(1) unsigned NOT NULL,
PRIMARY KEY (`item_id`),
FOREIGN KEY (user_id) REFERENCES users(user_id)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The SQL Fiddle is here.
I should point out a few other things:
Pay attention to the database engine you are using. MyISAM doesn't actually enforce the relationship.
Having weird dates as the default value is probably less useful than just using NULL.
I'm not sure if there is a value to having explicit collations for every character definition, unless your database is going to be supporting a wide variety of collations.
Don't use single quotes for numeric constants. So, if a value is declared as a tinyint, set the default ot 0 not '0' (this doesn't affect performance in a CREATE TABLE statement; it is just misleading).
#GordonLindoff's solution is one method, but that assumes that each item belongs to exactly one user, and an item cannot be referenced by multiple users. If you have a many-to-many relationship, where a user can have multiple items and an item can be referenced by multiple users, then you need a third table that links them together:
CREATE TABLE IF NOT EXISTS `user_item` (
`user_id` int(11) unsigned NOT NULL,
`item_id` int(11) unsigned NOT NULL,
PRIMARY KEY (`user_item`,`item_id`),
FOREIGN KEY (user_id) REFERENCES users(user_id),
FOREIGN KEY (item_id) REFERENCES items(item_id)
)ENGINE=Innodb DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
The Foreign Key constraints enforce that for every row in user_item that the user_id exists in users, and the item_id exists in items. And as was mentioned in a previous comment, that you will need Innodb to have the foreign key constraints enforced.

MySQL Long First Query Time

I have a website that has two main queries to the database which are pretty slow the first time they are run, after a bit of testing it appears to be an issue with MySQL. If I run the query directly in Sequal Pro when I run a query the first time it can take up to 4 seconds to run but running the same query again takes ~60ms, the query time is about the same locally as on our server, which make me think its not a server issue.
Not totally sure that increasing the buffer pool size will help too much as the number of potential query combinations is probably around 800K.
The tables in the database are innodb, both queries access the same table that has 52K records, most of the information I need has been grouped together into a 'searchfield' field which is indexed.
Only fields used in queries or are primary/foreign keys are being indexed.
I have tried changing the inner joins to a select statement in the "where" of the main query but this doesn't make the query any faster.
The queries are
Query 1
SELECT
`item_attribute`.`attribute_id` AS `attribute_id`,
`attribute_value_id` AS `attribute_value_id`,
`collection_attribute`.`title` AS `ca_title`,
`collection_attribute`.`type` AS `ca_type`,
`collection_attribute`.`is_collapsible` AS `ca_is_collapsible`,
`collection_attribute`.`orderindex` AS `ca_orderindex`,
`collection_attribute`.`multi_select` AS `ca_multi_select`,
`item_attribute`.`item_id` AS `item_id`,
`product`.`id` AS `product_id`
FROM `item_attribute`
INNER JOIN `item` ON item.id = item_attribute.item_id
INNER JOIN `product` ON product.id = item.product_id
INNER JOIN `collection_attribute` ON item_attribute.attribute_id = collection_attribute.attribute_id
INNER JOIN `attribute_value` ON attribute_value.id = item_attribute.attribute_value_id
WHERE ((`product`.`searchfilter` LIKE '%c:35∆%') AND (`collection_attribute`.`collection_id`='35')) AND (`attribute_value`.`active`=1)
GROUP BY `attribute_value_id`
Query 2
SELECT DISTINCT `item_attribute`.`attribute_id` AS `attribute_id`,
GROUP_CONCAT(item_attribute.attribute_value_id SEPARATOR \"-\") AS `attribute_value`,
GROUP_CONCAT(attribute_value.title SEPARATOR \" - \") AS `title`
FROM `item_attribute`
LEFT JOIN `item` ON item.id = item_attribute.item_id
LEFT JOIN `attribute` ON attribute.id = item_attribute.attribute_id
LEFT JOIN `attribute_value` ON attribute_value.id = attribute_value_id
WHERE (`item`.`product_id`='894') AND (`attribute`.`is_option`=1)
GROUP BY `attribute_id`, `item_id`
Table Structure
CREATE TABLE `product` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`slug` varchar(255) NOT NULL,
`sku` varchar(20) NOT NULL,
`active` tinyint(1) DEFAULT '0',
`orderindex` int(2) DEFAULT '-1',
`search` varchar(255) DEFAULT NULL,
`searchfilter` varchar(255) DEFAULT NULL,
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
`protected` tinyint(1) DEFAULT '0',
`description` varchar(512) DEFAULT NULL,
`type_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `product_ibfk_1` (`type_id`),
KEY `searchfilter` (`searchfilter`),
CONSTRAINT `product_ibfk_1` FOREIGN KEY (`type_id`) REFERENCES `attribute_value` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1882 DEFAULT CHARSET=utf8;
--
CREATE TABLE `collection_attribute` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`collection_id` int(11) DEFAULT NULL,
`attribute_id` int(11) DEFAULT NULL,
`title` varchar(512) NOT NULL,
`slug` varchar(512) NOT NULL,
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
`active` tinyint(1) DEFAULT '0',
`orderindex` int(2) DEFAULT '-1',
`search` varchar(255) DEFAULT NULL,
`searchfilter` varchar(255) DEFAULT NULL,
`protected` tinyint(1) DEFAULT '0',
`is_collapsible` tinyint(1) DEFAULT '0',
`type` enum('icon','checkbox','checkboxIcon','image') DEFAULT NULL,
`multi_select` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`),
KEY `collection_attribute_ibfk_1` (`collection_id`),
KEY `collection_attribute_ibfk_2` (`attribute_id`),
CONSTRAINT `collection_attribute_ibfk_1` FOREIGN KEY (`collection_id`) REFERENCES `collection` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `collection_attribute_ibfk_2` FOREIGN KEY (`attribute_id`) REFERENCES `attribute` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=140 DEFAULT CHARSET=utf8;
--
CREATE TABLE `item` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`slug` varchar(255) NOT NULL,
`title` varchar(255) NOT NULL,
`pattern_code` varchar(32) NOT NULL,
`tom_code` varchar(32) NOT NULL,
`navision_code` varchar(32) NOT NULL,
`description` varchar(255) DEFAULT NULL,
`active` tinyint(1) DEFAULT '0',
`orderindex` int(2) DEFAULT '-1',
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
`search` varchar(1024) DEFAULT NULL,
`searchfilter` varchar(255) DEFAULT NULL,
`product_id` int(11) DEFAULT NULL,
`protected` tinyint(1) DEFAULT '0',
`pattern_series` varchar(255) DEFAULT NULL,
`pattern_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `item_ibfk_1` (`product_id`),
KEY `searchfilter` (`searchfilter`),
KEY `product_id` (`product_id`),
KEY `pattern_id` (`pattern_id`),
CONSTRAINT `item_ibfk_1` FOREIGN KEY (`product_id`) REFERENCES `product` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `item_ibfk_2` FOREIGN KEY (`pattern_id`) REFERENCES `pattern_series` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=50060 DEFAULT CHARSET=utf8;
--
CREATE TABLE `item_attribute` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`item_id` int(11) NOT NULL,
`attribute_id` int(11) NOT NULL,
`attribute_value_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `attribute_id` (`attribute_id`),
KEY `attribute_value_id` (`attribute_value_id`),
KEY `item_id` (`item_id`),
CONSTRAINT `item_attribute_ibfk_1` FOREIGN KEY (`attribute_id`) REFERENCES `attribute` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `item_attribute_ibfk_2` FOREIGN KEY (`attribute_value_id`) REFERENCES `attribute_value` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `item_attribute_ibfk_3` FOREIGN KEY (`item_id`) REFERENCES `item` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=857111 DEFAULT CHARSET=utf8;
--
CREATE TABLE `attribute_value` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`slug` varchar(255) NOT NULL,
`code` varchar(255) DEFAULT NULL,
`title` varchar(255) NOT NULL,
`active` tinyint(1) DEFAULT '0',
`orderindex` int(2) DEFAULT '-1',
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
`search` varchar(255) DEFAULT NULL,
`searchfilter` varchar(255) DEFAULT NULL,
`attribute_id` int(11) DEFAULT NULL,
`protected` tinyint(1) DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3471 DEFAULT CHARSET=utf8;
--
CREATE TABLE `attribute` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL,
`slug` varchar(255) NOT NULL,
`code` varchar(255) DEFAULT NULL,
`is_option` tinyint(1) DEFAULT '0',
`searches` tinyint(1) DEFAULT '0',
`option_type` enum('dropdown','switch','fingersizes') DEFAULT NULL,
`option_label` varchar(32) DEFAULT NULL,
`active` tinyint(1) DEFAULT '0',
`orderindex` int(2) DEFAULT '-1',
`created_at` int(11) DEFAULT NULL,
`updated_at` int(11) DEFAULT NULL,
`search` varchar(255) DEFAULT NULL,
`searchfilter` varchar(255) DEFAULT NULL,
`protected` tinyint(1) DEFAULT '0',
`option_requires` int(11) DEFAULT NULL,
`option_depends` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `is_option` (`is_option`)
) ENGINE=InnoDB AUTO_INCREMENT=47 DEFAULT CHARSET=utf8;
Any suggestions on how to improve the initial query time would be great
Thanks in advance :)
-- EDIT --
EXPLAIN SELECT query 1
EXPLAIN SELECT query 2
The first time you perform a query after starting the server, nothing is cache, so the query needs to fetch stuff from disk. All subsequent queries that access the same parts of the same tables will be much faster because of caching. This is "normal".
If you have the "Query cache" enable (it is probably enabled by default), then the second time you run exactly the same query, it will instantly find the result from the Query cache. By "exactly" I mean that not so much as a blank space has changed. Nearly all "production" servers are better off turning off the Query cache.
innodb_buffer_pool_size should be about 70% of available RAM. Changing the value won't affect a SELECT against a cold cache, but might help/hurt subsequent runs. This does not seem to be relevant in your case, since the second run was quite fast.
Please provide EXPLAIN SELECT ... so we can see how the optimizer decided to execute them.
LIKE '%c:35∆%' -- cannot use an index because of the leading wild card.
What is item_ids?
item_attribute is an EAV schema pattern. It sucks. Both the queries are ugly, and scalability hurts. It may help some to get rid of the id and make a compound PRIMARY KEY from a suitable combination of the other fields. The hope is to use the PRIMARY KEY which is clustered with the data instead of having to bounce from the secondary key. More discussion of EAV.
Assuming this has low cardinality, the index will probably never be used:
KEY is_option (is_option)

Optimize SQL Query with GROUP BY

I need help with a query running slow when using group by:
SELECT `customers`.`id`
,`customers`.`firstname`
,`customers`.`lastname`
,`customers`.`address`
,`customers`.`address_co`
,`customers`.`country`
,`customers`.`zipcode`
,`customers`.`city`
,`customers`.`phone`
,`customers`.`mobilephone`
,`customers`.`ssn`
,`users`.`email`
,`customer_lists`.`name` AS `customerList`
,COUNT( transactions.id ) AS transactions_count
,SUM( transactions.sum_incl ) AS sum_incl
,SUM( transactions.sum_excl ) AS sum_excl
,`customers`.`created_at`
FROM `customers`
INNER JOIN `users`
ON `customers`.`user_id` = `users`.`id`
LEFT JOIN `transactions`
ON `customers`.`id` = `transactions`.`customer_id`
INNER JOIN `customer_lists`
ON `customers`.`customer_list_id` = `customer_lists`.`id`
WHERE `customer_lists`.`club_id` = '1'
GROUP BY `customers`.`id`
ORDER BY `customers`.`created_at` DESC
When I run a EXPLAIN it says Using temporary; Using filesort.
**id** **select_type** **table** **type** **possible_keys** **key** **key_len** **ref** **rows** **Extra**
1 SIMPLE customer_lists ref PRIMARY,club_id_index club_id_index 8 const 1 Using temporary; Using filesort
1 SIMPLE customers ref customers_user_id_foreign,customers_customer_list_... customers_customer_list_id_index 8 kund_workbox_nu.customer_lists.id 867
1 SIMPLE users eq_ref PRIMARY PRIMARY 8 kund_workbox_nu.customers.user_id 1
1 SIMPLE transactions ref customer_id_index customer_id_index 8 kund_workbox_nu.customers.id 3108
How do I fix that?
UPDATE
Tables:
Customers
CREATE TABLE `customers` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) unsigned NOT NULL,
`customer_list_id` bigint(20) unsigned NOT NULL,
`firstname` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`lastname` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`address` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`address_co` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`country` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`zipcode` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
`city` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`phone` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`mobilephone` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
`ssn` varchar(15) COLLATE utf8_unicode_ci NOT NULL,
`last_login` datetime NOT NULL,
`added_information` tinyint(1) NOT NULL DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `customers_user_id_foreign` (`user_id`),
KEY `customers_customer_list_id_index` (`customer_list_id`),
CONSTRAINT `customers_customer_list_id_foreign` FOREIGN KEY (`customer_list_id`) REFERENCES `customer_lists` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `customers_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=29739 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Transactions
CREATE TABLE `transactions` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`transaction_type_id` bigint(20) unsigned NOT NULL,
`customer_id` bigint(20) unsigned NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`sum_incl` decimal(15,4) NOT NULL,
`sum_excl` decimal(15,4) NOT NULL,
PRIMARY KEY (`id`),
KEY `transactions_customer_id_foreign` (`customer_id`),
KEY `transactions_transaction_type_id_foreign` (`transaction_type_id`),
CONSTRAINT `transactions_customer_id_foreign` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `transactions_transaction_type_id_foreign` FOREIGN KEY (`transaction_type_id`) REFERENCES `transaction_types` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=580116 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Customer Lists
CREATE TABLE `customer_lists` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`club_id` bigint(20) unsigned NOT NULL,
`name` varchar(90) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `customer_lists_club_id_foreign` (`club_id`),
CONSTRAINT `customer_lists_club_id_foreign` FOREIGN KEY (`club_id`) REFERENCES `clubs` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
Perhaps try a single table grouping on transactions as a derived table?
SELECT
`customers`.`id`
, `customers`.`firstname`
, `customers`.`lastname`
, `customers`.`address`
, `customers`.`address_co`
, `customers`.`country`
, `customers`.`zipcode`
, `customers`.`city`
, `customers`.`phone`
, `customers`.`mobilephone`
, `customers`.`ssn`
, `users`.`email`
, `customer_lists`.`name` AS `customerList`
, `trans`.transactions_count
, `trans`.sum_incl
, `trans`.sum_excl
, `customers`.`created_at`
FROM `customers`
INNER JOIN `users` ON `customers`.`user_id` = `users`.`id`
INNER JOIN `customer_lists` ON `customers`.`customer_list_id` = `customer_lists`.`id`
LEFT JOIN (
SELECT
`transactions`.`customer_id`
, COUNT(transactions.id) AS transactions_count
, SUM(transactions.sum_incl) AS sum_incl
, SUM(transactions.sum_excl) AS sum_excl
FROM `transactions`
GROUP BY `transactions`.`customer_id`
) `trans` ON `customers`.`id` = `trans`.`customer_id`
WHERE `customer_lists`.`club_id` = '1'
ORDER BY `customers`.`created_at` DESC
A where clause in that subquery may also help.
Have you tried to create indexes on all the JOIN columns, i.e. customers.user_id, users.id, transactions.customer_id, ... ?