How to query on a three mysql joined table? - mysql

I have three mysql table:
*page_category* table
CREATE TABLE `page_category` (
`id_page` VARCHAR(255) NOT NULL,
`name` VARCHAR(255) DEFAULT NULL,
`search_here` TEXT,
PRIMARY KEY (`id_page`),
FULLTEXT KEY `search` (`search_here`)
) ENGINE=MYISAM DEFAULT CHARSET=latin1
*page_category* table contains more than 2 million rows of data.
*user_page* table
CREATE TABLE `user_page` (
`user_id` VARCHAR(255) NOT NULL,
`id_page` VARCHAR(255) NOT NULL,
PRIMARY KEY (`user_id`,`id_page`)
) ENGINE=INNODB DEFAULT CHARSET=latin1
*user_page* table contains more than 10 million rows of data.
*user_relationship* table
CREATE TABLE `user_relationship` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`me` VARCHAR(255) DEFAULT NULL,
`friend` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `me_friend` (`me`,`friend`)
) ENGINE=INNODB AUTO_INCREMENT=7517967 DEFAULT CHARSET=latin1
*user_relationship* table contains more than 1 million rows of data.
I do a query:
SELECT a.id_page AS ids, b.user_id,
a.name AS nama, c.me,
COUNT(c.me) AS nfriend,
GROUP_CONCAT(b.user_id SEPARATOR ',') AS friendlist
FROM
page_category a
LEFT JOIN user_page b
ON a.id_page = b.id_page
LEFT JOIN user_relationship c
ON
b.user_id = c.friend
WHERE
c.me='12' AND
MATCH(a.search_here) AGAINST('+book' IN BOOLEAN MODE);
results are shown in a very long time. am I wrong on writing the query?

You need to add proper indexing as well as you need to make query so that it has less temp. You can change order of join and explain it to debug your query to ger the best one.

Related

I need to optimize tables and queries

I have 3 tables: info, data, link, there is a request for data:
select *
from data,link,info
where link.info_id = info.id and link.data_id = data.id
offer optimization options:
a) tables
b) request.
Queries for creating tables:
CREATE TABLE info (
id int(11) NOT NULL auto_increment,
name varchar(255) default NULL,
desc text default NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
CREATE TABLE data (
id int(11) NOT NULL auto_increment,
date date default NULL,
value INT(11) default NULL,
PRIMARY KEY (id)
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
CREATE TABLE link (
data_id int(11) NOT NULL,
info_id int(11) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=cp1251;
Thanks!
Never use commas in the FROM clause. Always use proper, explicit, standard, readable JOIN syntax:
select *
from data d join
link l
on l.data_id = d.id join
info i
on l.info_id = i.id;
Second, for this query your indexes are probably fine. I would also recommend a primary key index on link:
CREATE TABLE link (
data_id int(11) NOT NULL,
info_id int(11) NOT NULL,
PRIMARY KEY (data_id, info_id)
);
This is a good idea in general, even if it is not specific to this query.

performance issue when joining two large tables

I have a multilingual CMS that uses a translation table (70k rows) that contains all of the texts
CREATE TABLE IF NOT EXISTS `translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` int(11) NOT NULL,
`lang` int(11) NOT NULL,
`value` text CHARACTER SET utf8,
PRIMARY KEY (`id`),
KEY `key` (`key`,`lang`)
) ENGINE=MyISAM
and products table (4k rows) containing products with translation keys
CREATE TABLE IF NOT EXISTS `products` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name_trans_id` int(11) NOT NULL,
`desc_trans_id` int(11) DEFAULT NULL,
`text_trans_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `name_index` (`name_trans_id`),
KEY `desc_index` (`desc_trans_id`),
KEY `text_index` (`text_trans_id`)
) ENGINE=MyISAM
now i need to get top 20 products in alphabetical order, to do that i use this query :
SELECT
SQL_CALC_FOUND_ROWS
dt_table.* ,
t_name.value as 'name'
FROM
products as dt_table
LEFT JOIN
`translations` as t_name on dt_table.name_trans_id = t_name.key
WHERE
(t_name.lang = 1 OR t_name.lang is null)
ORDER BY
name ASC LIMIT 0, 20
It takes forever.
Any help optimizing this query/tables will be appreciated.
Thank you.
Try to change your structure of translations table to:
CREATE TABLE IF NOT EXISTS `translations` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` int(11) NOT NULL,
`lang` int(11) NOT NULL DEFAULT 0,
`value` text CHARACTER SET utf8,
PRIMARY KEY (`id`),
KEY `lang` (`lang`),
KEY `key` (`key`,`lang`),
FULLTEXT idx (`value`)
) ENGINE=InnoDB;
because you really need lang to be indexed as soon as you use it in WHERE clause.
And try to change your query a little bit:
SELECT
dt_table.* ,
t_name.value as 'name',
SUBSTR(t_name.value,0,100) as text_order
FROM
products as dt_table
LEFT JOIN (
SELECT key, value FROM `translations`
WHERE lang = 1 OR lang is null
) as t_name
ON dt_table.name_trans_id = t_name.key
ORDER BY
text_order ASC LIMIT 0, 20
and if you really need SQL_CALC_FOUND_ROWS (I don't understand why do you need counter for translations items)
you can run another query just right after the first one:
SELECT COUNT(*) FROM products;
I am pretty sure you will be surprised with performance :-)

How do I join three fields from three tables in MySQL?

I have three fields from three different tables that I would like to join together.
company FROM company,
title FROM jobs,
Description FROM jobcategory
I would like to have these three fields join together and listed sequentially to the right of the prvious field as follows:
Company | Title | Description
This is the best I can do as for providing information regarding the databases Keys...
CREATE TABLE `company` (
`companyID` int(11) NOT NULL AUTO_INCREMENT,
`company` varchar(255) NOT NULL,
PRIMARY KEY (`companyID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=117 ;
CREATE TABLE `jobcategory` (
`JobCategoryID` int(11) NOT NULL AUTO_INCREMENT,
`CategoryName` text,
`Description` text,
PRIMARY KEY (`JobCategoryID`),
UNIQUE KEY `unique_JobCategoryID` (`JobCategoryID`),
KEY `index_JobCategoryID` (`JobCategoryID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=11 ;
CREATE TABLE `jobs` (
`title` varchar(255) NOT NULL,
`company` varchar(255) NOT NULL,
`date` date NOT NULL,
`companyID` int(11) NOT NULL,
`jobCategoryID` int(11) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
I tried running a query commented below, I received the following error.
"Error 1054 (42S22) : Unknown column 'Company.ID' in "on clause'
What is the proper syntax to execute this query?
Depends on how your keys are set up, but assuming JOBS has foreign keys referencing the COMPANY and JOBCATEGORY tables:
SELECT COMPANY.COMPANY, JOBS.TITLE, JOBCATEGORY.DESCRIPTION<br>
FROM COMPANY
INNER JOIN JOBS ON COMPANY.ID=JOBS.COMPANY_ID
INNER JOIN JOBCATEGORY ON JOBCATEGORY.ID=JOBS.JOBCATEGORY_ID

Optimize sql query to speed up a search which currently takes around 85 seconds

I have a database with the records near about 2.7 milion . I need to fetch records from that for that i am using the below query
for result
SELECT r3.original_image_title,r3.uuid,r3.original_image_URL FROM `image_attributes` AS r1 INNER JOIN `filenames` as r3 WHERE r1.`uuid` = r3.`uuid` and r3.`status` = 1 and r1.status=1 and (r1.`attribute_name` like "Quvenzhané Wallis%" or r3.original_image_URL like "Quvenzhané Wallis%") group by r3.`uuid` limit 0,20
for total count
SELECT count(DISTINCT(r1.`uuid`)) as count FROM `image_attributes` AS r1 INNER JOIN `filenames` as r3 WHERE r1.`uuid` = r3.`uuid` and r3.`status` = 1 and r1.status=1 and (r1.`attribute_name` like "Quvenzhané Wallis%" or r3.original_image_URL like "Quvenzhané Wallis%")
table structures are as below
CREATE TABLE IF NOT EXISTS `image_attributes` (
`index` int(11) NOT NULL AUTO_INCREMENT,
`attribute_name` text NOT NULL,
`attribute_type` varchar(255) NOT NULL,
`uuid` varchar(255) NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '1',
PRIMARY KEY (`index`),
KEY `attribute_type` (`attribute_type`),
KEY `uuid` (`uuid`),
KEY `status` (`status`),
KEY `attribute_name` (`attribute_name`(50))
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=2730431 ;
CREATE TABLE IF NOT EXISTS `filenames` (
`index` int(11) NOT NULL AUTO_INCREMENT,
`original_image_title` text NOT NULL,
`original_image_URL` text NOT NULL,
`uuid` varchar(255) NOT NULL,
`status` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`index`),
KEY `uuid` (`uuid`),
KEY `original_image_URL` (`original_image_URL`(50))
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=591967 ;
please suggest me how can i optimize the queries to make the search result faster
I would recommend to you a book called 'High Performance MySql'. There is a section called Optimize databases and queries, or something like that.

How to apply the MINUS efficiently on mysql query for tables with large data

I have 2 tables as the following -
CREATE TABLE IF NOT EXISTS `nl_members` (
`member_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`member_email` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`member_confirmation_code` varchar(35) COLLATE utf8_unicode_ci NOT NULL,
`member_enabled` enum('Yes','No') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Yes',
PRIMARY KEY (`member_id`),
UNIQUE KEY `TUC_nl_members_1` (`member_email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci AUTO_INCREMENT=58520 ;
CREATE TABLE IF NOT EXISTS `nl_member_group_xref` (
`group_id` int(10) unsigned NOT NULL,
`member_id` int(10) unsigned NOT NULL,
`member_subscribed` enum('Yes','No') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Yes',
`subscribe_date` int(10) unsigned NOT NULL DEFAULT '0',
`unsubscribe_date` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`group_id`,`member_id`),
KEY `nl_members_nl_member_group_xref` (`member_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `nl_member_group_xref`
ADD CONSTRAINT `nl_members_nl_member_group_xref` FOREIGN KEY (`member_id`) REFERENCES `nl_members` (`member_id`),
ADD CONSTRAINT `nl_member_groups_nl_member_group_xref` FOREIGN KEY (`group_id`) REFERENCES `nl_member_groups` (`group_id`);
Both has quite some large amount of data about millions of them.
What i want is to have an efficient was of applying the MINUS on result set.
For example,
i want to get all the users from Group1 with ID: 1 MINUS all users from Group2 with ID: 2 and Group3 with ID: 3
How can i do it efficiently? with the query running as fast as possible.
Update
What i want is like this -
in members table 'nl_members' i keep a list of all members, who could have been associated with one or more groups.
for each group association for a member there will be a row in the 'nl_member_group_xref' table.
so if a member is associated with 3 groups there will be 3 entries in the member_group_xref table.
Now what i want is to get all members included in group 1 but exclude members if they also belong to group 2 and group 3.
Hope this helps.
For your updated question you will need to join the two tables and group it with members_id: See below query if will display the result your looking for.
UPDATED:
SELECT
nm.*, nmgx.*
FROM nl_members nm
INNER JOIN nl_member_group_xref nmgx
ON nm.member_id = nmgx.member_id
LEFT JOIN (SELECT
nmgx2.member_id
FROM nl_member_group_xref nmgx2
WHERE nmgx2.group_id <> 1) nmgx22
ON nmgx22.member_id = nm.member_id
WHERE nmgx22.member_id IS NULL
GROUP BY nm.member_id;
Note: I used * to get all the field name. You get specific field so the query will be more faster as it only get less results. Ex. member_id like nm.member_id
If this is not what you looking for, just inform me then I'll update this query as accurate as I can
Have you tried using the MINUS operator?