- Total profiles – 100000
- Each profile is connected to one or more platform
- Each profile have 50 Tags
- Each profile have 4 themes
I have a user view (total users around 100000) where I am joining all the user data and getting it at once place. My current view query is given below:
SELECT (fields to select)
FROM profiles
LEFT JOIN profile_calculated_totals ON (profiles.id = profile_calculated_totals.profile_id)
LEFT JOIN platform_one ON ((platform_one.private = 'N') AND(profiles.platform_one = platform_one.id))
LEFT JOIN platform_two ON (profiles.platform_two = platform_two.id)
LEFT JOIN platform_three ON (profiles.platform_three = platform_three.id)
LEFT JOIN (
SELECT profiles_tags.profile_id, GROUP_CONCAT(tags.tag) as profile_tags
FROM profiles_tags
JOIN tags ON(profiles_tags.tag_id = tags.id)
GROUP BY profiles_tags.profile_id
)as X ON (profiles.id = X.profile_id)
LEFT JOIN (
SELECT profiles_themes.profile_id, GROUP_CONCAT(themes.name) as profile_themes
FROM profiles_themes
JOIN themes ON(profiles_themes.theme_id = themes.id)
GROUP BY profiles_themes.profile_id
)as Y ON (profiles.id = Y.profile_id)
WHERE profiles.verified = 'Y'
If I will run the view or this raw query it takes around 2-3 seconds to load. SELECT * FROM profile_view LIMIT 0,50
To optimize query I did some research and found out about the VIEW ALGOs TEMPTABLE
and MERGE
+ I did EXPLAIN
to the query and found out there are lot of derived tables, so I rewrite the query as below:
SELECT (fields to select)
FROM profiles
LEFT JOIN profile_calculated_totals ON (profiles.id = profile_calculated_totals.profile_id)
LEFT JOIN platform_one ON ((platform_one.private = 'N') AND(profiles.platform_one = platform_one.id))
LEFT JOIN platform_two ON (profiles.platform_two = platform_two.id)
LEFT JOIN platform_three ON (profiles.platform_three = platform_three.id)
LEFT JOIN profiles_tags ON(profiles.id = profiles_tags.profile_id)
LEFT JOIN tags ON(profiles_tags.tag_id = tags.id)
LEFT JOIN profiles_themes ON(profiles.id = profiles_themes.profile_id)
LEFT JOIN themes ON(profiles_themes.theme_id = themes.id)
WHERE (profiles.verified = 'Y')
GROUP BY profiles.id
ORDER BY profile_calculated_totals.total_followers DESC
EXPLAIN
result
If I will run this query, it's very fast and showing the results 0.5 seconds but when I will apply ORDER BY
with this query it's taking 10-12 Seconds (here I have already created index for column profile_id
)
Now, one of the solutions I am thinking is saving the profile tags as comma separated in DB(this is solving all the problems speed and sort both) but I have seen lot of posts on Internet that it's not RDBMS way and will create problems in future.
The Table structures involved in this are given below:
profiles ->
`CREATE TABLE `profiles` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`slug` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`gender` enum('male','female','transgender') CHARACTER SET latin1 COLLATE latin1_swedish_ci DEFAULT NULL,
`url` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`email` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`audience` enum('male','female','both') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`birthday` date DEFAULT NULL,
`age_min` int(2) DEFAULT NULL,
`age_max` int(2) DEFAULT NULL,
`phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`address_1` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`address_city` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`bio` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`country` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`continent` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`languages` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`platform_two` bigint(20) unsigned DEFAULT NULL,
`platform_one` bigint(20) unsigned DEFAULT NULL,
`platform_three` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`score` int(2) unsigned NOT NULL DEFAULT '0',
`verified` enum('Y','N') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'Y',
`kind` enum('influencer','brand') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'influencer',
`sub_kind` enum('blogger','platform_oneer','platform_threer','model','artist','celebrity','magazine') CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`blogger_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`agent_address` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`agent_city` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`agent_country` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`agent_continent` varchar(2) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`agent_phone` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`agent_email` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`salesforce_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `slug` (`slug`),
UNIQUE KEY `platform_one` (`platform_one`),
UNIQUE KEY `platform_two` (`platform_two`),
UNIQUE KEY `platform_three` (`platform_three`)
) ENGINE=InnoDB AUTO_INCREMENT=34985 DEFAULT CHARSET=utf8mb4
COLLATE=utf8mb4_unicode_ci
platform_one –
CREATE TABLE `platform_one` (
`id` bigint(20) unsigned NOT NULL,
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`website` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`bio` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`media` int(10) DEFAULT NULL,
`followed_by` int(10) DEFAULT NULL,
`follows` int(10) DEFAULT NULL,
`profile_picture` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`is_verified` tinyint(1) DEFAULT '0',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `platform_one_id_profiles_platform_one` FOREIGN KEY (`id`)
REFERENCES `profiles` (`platform_one`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
platform_two ->
CREATE TABLE `platform_two` (
`id` bigint(20) unsigned NOT NULL,
`username` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`picture` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`about` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`birthday` date DEFAULT NULL,
`category` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`likes` bigint(20) DEFAULT NULL,
`engagement_rate` decimal(6,2) DEFAULT NULL,
`media_value` decimal(20,2) DEFAULT NULL,
`growth` decimal(4,2) DEFAULT NULL,
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`website` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`release_date` date DEFAULT NULL,
`general_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`personal_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`bio` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`personal_interests` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`phone` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
CONSTRAINT `profiles_platform_two_platform_two_id` FOREIGN KEY (`id`) REFERENCES `profiles` (`platform_two`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
platform_three ->
CREATE TABLE `platform_three` (
`id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`name` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`picture` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci,
`upload_playlist_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`view_count` int(10) unsigned DEFAULT NULL,
`comment_count` int(10) unsigned DEFAULT NULL,
`subscriber_count` int(10) unsigned DEFAULT NULL,
`video_count` int(10) unsigned DEFAULT NULL,
`engagement_rate` decimal(6,2) DEFAULT NULL,
`media_value` decimal(20,2) DEFAULT NULL,
`growth` decimal(4,2) DEFAULT NULL,
`published_at` int(10) unsigned DEFAULT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `upload_playlist_id` (`upload_playlist_id`),
KEY `engagement_rate` (`engagement_rate`),
CONSTRAINT `profiles_platform_three_platform_three_id` FOREIGN KEY (`id`) REFERENCES `profiles` (`platform_three`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
profile_calculated_totals ->
CREATE TABLE `profile_calculated_totals` (
`profile_id` int(11) NOT NULL,
`total_followers` bigint(20) NOT NULL COMMENT 'total followers of the profile',
`total_eg_rate` decimal(12,6) NOT NULL COMMENT 'total EG rate of the profile',
`total_growth` decimal(12,6) NOT NULL COMMENT 'total Growth of the profile',
PRIMARY KEY (`profile_id`),
KEY `total_followers` (`total_followers`),
KEY `total_eg_rate` (`total_eg_rate`),
KEY `total_growth` (`total_growth`),
CONSTRAINT `profile_calculated_totals_profile_id_profiles_id` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='table contains the total calculated values for the profile'
profiles_tags ->
CREATE TABLE `profiles_tags` (
`profile_id` int(11) NOT NULL,
`tag_id` int(11) unsigned NOT NULL,
`occurrences` int(11) NOT NULL,
PRIMARY KEY (`profile_id`,`tag_id`),
KEY `tag_id` (`tag_id`),
CONSTRAINT `profiles_tags_profile_id_profiles_id` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `profiles_tags_tag_id_tags_id` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
tags ->
CREATE TABLE `tags` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`tag` varchar(190) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `hashtag` (`tag`)
) ENGINE=InnoDB AUTO_INCREMENT=700840 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
profiles_themes ->
CREATE TABLE `profiles_themes` (
`profile_id` int(11) NOT NULL,
`theme_id` int(11) NOT NULL,
PRIMARY KEY (`profile_id`,`theme_id`),
KEY `profiles_themes_theme_id_themes_id` (`theme_id`),
CONSTRAINT `profiles_themes_profile_id_profiles_id` FOREIGN KEY (`profile_id`) REFERENCES `profiles` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `profiles_themes_theme_id_themes_id` FOREIGN KEY (`theme_id`) REFERENCES `themes` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
themes ->
CREATE TABLE `themes` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(150) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
Best Answer
If that is the VIEW, let's see a SELECT (or whatever) using it.
A common optimization is to avoid
LEFT JOIN (SELECT..)
thus:-->
Ditto for
profile_themes
Many-to-many tables are costly because of this 2-hop you have to do. It may be better, in the long run, to have the
tag
in the many-to-many table and get rid of the tabletags
.Then it becmes