How can I optimize the MYSQL query related to regions - mysql

Country table has around 2 records.
State table has around 50 records.
City table has around 6000 records.
Zipcode table has around 500000 records
Approximate exicution time to fetch data is around 12-15 minutes.
How can I optimize below query:
SELECT Country.id AS Country_id,
Country.country AS Country_country,
Country.countrycode AS Country_countrycode,
State.id AS State_id,
State.statecode AS State_statecode,
City.id AS City_id,
City.city AS City_city,
Zipcode.id AS Zipcode_id,
Zipcode.zipcode AS Zipcode_zipcode
FROM c_country Country
LEFT JOIN c_state State
ON Country.id = ( State.country_id )
LEFT JOIN c_city City
ON State.id = ( City.state_id )
LEFT JOIN c_zipcode Zipcode
ON City.id = ( Zipcode.city_id )
Below are the table structure:
CREATE TABLE `c_city` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`state_id` int(11) NOT NULL,
`city` varchar(256) NOT NULL,
`zone_id` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7027 DEFAULT CHARSET=latin1;
CREATE TABLE `c_state` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country_id` int(11) NOT NULL,
`state` varchar(256) NOT NULL,
`statecode` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=latin1;
CREATE TABLE `c_country` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`country` varchar(256) NOT NULL,
`countrycode` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
CREATE TABLE `c_zipcode` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`city_id` int(11) NOT NULL,
`zipcode` varchar(256) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=539420 DEFAULT CHARSET=latin1;
Below is the screenshot of EXPLAIN SELECT:

for try to improve performanbce you could add index for
table c_zipcode column city_id
table c_city column state_id
table c_state column country_id
or for resolve too all the columns values using the index
table c_zipcode column city_id, zipcode
table c_city column state_id, city
table c_state column country_id , statecode

I think your query is very slow because there is some index missing. You didn't declare any Foreign Key, in mysql InnoDB, Foreign Key are important because they are warranty for the data integrity but MySQL create automatically index on this foreign keys too.
a link to explain : https://dba.stackexchange.com/questions/105469/performance-impact-of-adding-a-foreign-key-to-a-1m-rows-table
You have to alter the tables to add foreign keys :
ALTER TABLE c_city ADD CONSTRAINT fk_state_id FOREIGN KEY (state_id) REFERENCES c_state(id);
ALTER TABLE c_state ADD CONSTRAINT fk_country_id FOREIGN KEY (country_id) REFERENCES c_country(id);
ALTER TABLE c_zipcode ADD CONSTRAINT fk_city_id FOREIGN KEY (city_id) REFERENCES c_city (id);

Related

Foreign key cannot be created id MySQL: missing index on column(s)

I have a few foreign keys set up, however phpMyAdmin would not let me to create one more. Here are table in question:
Groups Table
id
name
address
Tasks Table
id
group_id
name
I need a foreign key on group_id in Tasks Table, but when I try to create in it provides the following error: Missing index on column(s). If I add a unique constrain on group_id I am then able to create the foreign key, but the ralation then becomes One to One, which is not the expected result.
Following are table create statements:
CREATE TABLE IF NOT EXISTS `groups` (
`id` int(11) NOT NULL,
`name` varchar(256) NOT NULL,
`address` varchar(256) NOT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1;
ALTER TABLE `groups`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`), ADD UNIQUE KEY `id_2` (`id`);
CREATE TABLE IF NOT EXISTS `tasks` (
`id` int(11) NOT NULL,
`group_id` int(11) NOT NULL,
`name` varchar(256) NOT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1;
ALTER TABLE `fixed_tasks`
ADD PRIMARY KEY (`id`), ADD UNIQUE KEY `id` (`id`);
Any help or guidance is much appreciated.
The following code can create two tables with relative foreign keys:
CREATE TABLE `Groups` (
`id` INT NOT NULL,
`name` VARCHAR(45) NULL,
`address` VARCHAR(45) NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE `Tasks` (
`id` INT NOT NULL,
`group_id` INT NULL,
`name` VARCHAR(45) NULL,
PRIMARY KEY (`id`),
CONSTRAINT `group_id`
FOREIGN KEY (`group_id`)
REFERENCES `Groups` (`id`)
);

Foreign Key Constraints In MySQL DB Gives Error

am trying to implement a foreign key constraint but the mysql keeps giving me an error There are two tables "groups" table and "members" table.I have a many to many relationship between these tables and therefore used a third table called "members_groups" table for the many to many relationship. Note: "groups" and "members" tables have been created and contain data but I now want to add the "members_groups" table. Below are the sql codes:
Below is the script for the members table.
CREATE TABLE IF NOT EXISTS `members` (
`member_id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(30) NOT NULL,
`email` varchar(50) NOT NULL,
`password` char(128) NOT NULL,
`salt` char(128) NOT NULL,
`group_id` bigint(64) unsigned NOT NULL,
`perm_override_add` bigint(64) unsigned NOT NULL,
`perm_override_remove` bigint(64) unsigned NOT NULL,
PRIMARY KEY (`member_id`),
KEY `member_id` (`member_id`)
) ENGINE=InnoDB;
script for the groups table
CREATE TABLE IF NOT EXISTS `groups` (
`group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`group_name` varchar(50) NOT NULL,
`permission` int(10) unsigned DEFAULT NULL,
PRIMARY KEY (`group_id`)
) ENGINE=InnoDB
script for the members_groups table
CREATE TABLE members_groups
(
member_id INT(11) NOT NULL ,
group_id INT(10) NOT NULL ,
PRIMARY KEY (member_id, group_id),
FOREIGN KEY (member_id) REFERENCES members(member_id) ON UPDATE CASCADE,
FOREIGN KEY (group_id) REFERENCES groups(group_id) ON UPDATE CASCADE
) ENGINE = InnoDB
This is the error I get from the mysql admin console.
Thanks.
You need to make the type same in your table. In your groups table you have defined
`group_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
whereas in your members_groups table it is
group_id INT(10) NOT NULL ,
Try to make the change like
CREATE TABLE members_groups
(
member_id INT(11) NOT NULL ,
group_id INT(10) unsigned NOT NULL , --The datatype should be same as group_id in `groups` table
PRIMARY KEY (member_id, group_id),
FOREIGN KEY (member_id) REFERENCES members(member_id) ON UPDATE CASCADE,
FOREIGN KEY (group_id) REFERENCES `groups`(group_id) ON UPDATE CASCADE
) ENGINE = InnoDB;
SQL FIDDLE DEMO

Lookup table in MySQL

I'm doing my first work in PHP/MySQL & I need help. I have one master table:
CREATE TABLE `m4l_movies` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Title` varchar(250) NOT NULL,
`Rating` int(11) NOT NULL,
`Genre` varchar(250) NOT NULL,
`Actors` varchar(250) NOT NULL,
`UserID` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM AUTO_INCREMENT=115 DEFAULT CHARSET=utf8;
that receives input for a form which has values from a these lookup tables:
CREATE TABLE `m4l_actors` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Actor` varchar(255) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=232 DEFAULT CHARSET=utf8;
CREATE TABLE `m4l_genre` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Genre` varchar(255) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=202 DEFAULT CHARSET=utf8;
CREATE TABLE `m4l_movierating` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Movie_Rating` varchar(250) NOT NULL,
PRIMARY KEY (`ID`)
) ENGINE=MyISAM AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
& I've created a View:
SELECT m4l_movies.ID AS ID,
m4l_movies.Title AS Title,
m4l_movierating.Movie_Rating AS Rating,
m4l_movies.Actors AS Actors,
m4l_movies.Genre AS Genre
FROM m4l_movies
JOIN m4l_movierating ON m4l_movierating.ID = m4l_movies.Rating
INNER JOIN m4l_genre ON m4l_movies.Genre = m4l_genre.ID
INNER JOIN m4l_actors ON m4l_movies.Actors = m4l_actors.ID
ORDER BY m4l_movies.Title
Here is the out put I get:
----------------------------------------------------------------|
ID Title Rating Actor Genre |
10 Summer G (10,15,25) (45,115,123) |
1 About You G-1 (63,163,405) (3,16,51) |
5 Dog Years P (45,65,95) (98,163,357) |
----------------------------------------------------------------|
Firstly this view should return more than 200 records. Secondly, I need to know how to either create a lookup or some other method to convert the NAME & GENRE back to their corresponding text values. Some how the RATING value is doing it right but I can't get NAME or GENRE to do it correctly. I'm sure it has to do with either the way I've joined the tables but I can't figure out where I'm going wrong. Will someone PLEASE help me.
Ok trying to follow along with suggesting made by Phil I've removed actors, genre from movies tale & created movies_genre & movies_actors
DROP TABLE IF EXISTS `m4l_movies`;
CREATE TABLE `m4l_movies` (
`ID` int(11) NOT NULL auto_increment,
`Title` varchar(250) NOT NULL,
`Year` float NOT NULL,
`Review` varchar(250) NOT NULL,
`Rating` int(11) NOT NULL,
`Image` varchar(250) NOT NULL,
`Storyline` longtext NOT NULL,
`Director` varchar(250) NOT NULL,
`UserID` int(11) NOT NULL default '1',
PRIMARY KEY (`ID`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
CREATE TABLE `m4l_movie_actor` (
movie_id INT(11),
actor_id INT(11),
PRIMARY KEY (movie_id, actor_id),
FOREIGN KEY (movie_id) REFERENCES m4l_movies (ID),
FOREIGN KEY (actor_id) REFERENCES m4l_actors (ID)
);
CREATE TABLE `m4l_movie_genre` (
movie_id INT(11),
genre_id INT(11),
PRIMARY KEY (movie_id, genre_id),
FOREIGN KEY (movie_id) REFERENCES m4l_movies (ID),
FOREIGN KEY (genre_id) REFERENCES m4l_genre (ID)
);
DROP TABLE IF EXISTS m4l_genre;
CREATE TABLE m4l_genre (
ID int(11) NOT NULL auto_increment,
Genre varchar(250) NOT NULL,
PRIMARY KEY (ID)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS m4l_actors;
CREATE TABLE m4l_actors (
ID int(11) NOT NULL auto_increment,
Actor varchar(255) NOT NULL,
PRIMARY KEY (ID)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
but when I try to create the movie_actor OR movie_genre I get
09:29:45
CREATE TABLE `m4l_movie_actor` (movie_id INT(11), actor_id INT(11),
PRIMARY KEY (movie_id, actor_id),
FOREIGN KEY (movie_id) REFERENCES m4l_movies (ID),
FOREIGN KEY (actor_id) REFERENCES m4l_actors (ID) )
Error Code: 1215. Cannot add foreign key constraint
0.000 sec
09:40:56 CREATE TABLE m4l_movie_genre (movie_id INT(11),genre_id INT(11),
PRIMARY KEY (movie_id, genre_id),
FOREIGN KEY (movie_id) REFERENCES m4l_movies (ID),
FOREIGN KEY (genre_id) REFERENCES m4l_genre (ID) )
Error Code: 1215. Cannot add foreign key constraint
0.016 sec
From what I can gather this only occurs when you have data types mismatch, but I THINK I have all INT data types so why am I getting this error?
You appear to have made the classic blunder of storing relational data in an un-relatable way.
You should be using junction tables instead of comma separated values. For example...
CREATE TABLE `m4l_movies` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`Title` varchar(250) NOT NULL,
`Rating` int(11) NOT NULL,
-- removed Actors and Genre
`UserID` int(11) NOT NULL DEFAULT '1',
PRIMARY KEY (`ID`)
);
CREATE TABLE `m4l_movie_actor` (
movie_id INT(11) NOT NULL,
actor_id INT(11) NOT NULL,
PRIMARY KEY (movie_id, actor_id),
FOREIGN KEY (movie_id) REFERENCES m4l_movies (ID),
FOREIGN KEY (actor_id) REFERENCES m4l_actors (ID)
);
-- repeat for genres
You can then join on the junction table and on to the Actors / Genres tables, eg
SELECT ... m4l_actors.Actor ...
FROM m4l_movies
INNER JOIN m4l_movie_actor ON m4l_movies.ID = m4l_movie_actor.movie_id
INNER JOIN m4l_actors ON m4l_movie_actor.actor_id = m4l_actors.ID
If you want the result in a comma separated list, look into GROUP_CONCAT()

Joining 3+ tables using SQL displaying too many results

im trying to create a query to join these tables together using this method below. However it is repeating results and they are not linking up correctly. as in the same rating comment would be on about 4/5 different results etc. its producing 18ish results when im expecting 3. would anyone be willing to help me with this problem?
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a,
Users b,
Ratings c,
UserCompJobRating d,
Company_Job e,
Jobs f
WHERE d.Comp_job_ID = e.Comp_Job_ID
AND b.users_ID = d.users_ID
AND c.Rating_ID = d.Rating_ID;
Many Thanks,
Andrew
ok i tried this and it is saying e.Users_ID is an unknown column in 'on clause'
SELECT a.Company_name,
b.Job_ID,
b.Job_Name,
c.User_Name,
d.Comments,
d.Reliability,
d.Rating
FROM Company a, UserCompJobRating e, Jobs b
INNER JOIN Users c
ON c.Users_ID = e.Users_ID
inner join Company_Job f
on e.Comp_Job_ID = f.Comp_Job_ID
inner join Ratings d
on d.Rating_ID = e.Rating_ID;
I'm assuming im close, however way off at the same time?
Ill try to give you some more information:
UserCompJobRating has a primary key UCJR_ID and 3 foreign keys of Comp_Job_ID, Users_ID and Rating_ID
Company_Job table as a primary key Comp_Job_ID, and 2 foreign keys Job_ID, Company_ID
Ratings Table has just the Rating_ID as a primary key and the rest just to do with the rating information
Users Table has a Users_ID as a primary key and basic user information address etc etc
Jobs Table has a Job_ID primary key and basic information about the job, such as name, price, etc.
Company Table has Company_ID as a primary key and the basic company information, similar to the Users table.
Here are the definations:
CREATE TABLE `company` (
`Company_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_Name` varchar(45) NOT NULL,
`CAddress` varchar(45) NOT NULL,
`CTown` varchar(45) NOT NULL,
`CPostcode` varchar(12) NOT NULL,
`CTelephone` varchar(45) NOT NULL,
PRIMARY KEY (`Company_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
CREATE TABLE `company_job` (
`Comp_Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Company_ID` int(11) NOT NULL,
`Job_ID` int(11) NOT NULL,
PRIMARY KEY (`Comp_Job_ID`),
KEY `Company_ID_idx` (`Company_ID`),
KEY `Job_ID_idx` (`Job_ID`),
CONSTRAINT `Company_ID` FOREIGN KEY (`Company_ID`) REFERENCES `company` (`Company_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Job_ID` FOREIGN KEY (`Job_ID`) REFERENCES `jobs` (`Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION
CREATE TABLE `jobs` (
`Job_ID` int(11) NOT NULL AUTO_INCREMENT,
`Job_Name` varchar(45) NOT NULL,
`Job_Cost` varchar(45) DEFAULT NULL,
`Job_Avg_Time` varchar(45) DEFAULT NULL,
`Job_Avg_Cost` varchar(45) DEFAULT NULL,
`Job_Description` varchar(45) NOT NULL,
`Company_ID` int(11) NOT NULL,
PRIMARY KEY (`Job_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `ratings` (
`Rating_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comments` varchar(200) DEFAULT NULL,
`Cost` varchar(45) DEFAULT NULL,
`Reliability` varchar(45) DEFAULT NULL,
`Rating` int(11) DEFAULT NULL,
PRIMARY KEY (`Rating_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `usercompjobrating` (
`UCJR_ID` int(11) NOT NULL AUTO_INCREMENT,
`Comp_Job_ID` int(11) DEFAULT NULL,
`Rating_ID` int(11) DEFAULT NULL,
`Users_ID` int(11) DEFAULT NULL,
PRIMARY KEY (`UCJR_ID`),
KEY `Comp_Job_ID_idx` (`Comp_Job_ID`),
KEY `Rating_ID_idx` (`Rating_ID`),
KEY `User_ID_idx` (`Users_ID`),
CONSTRAINT `Comp_Job_ID` FOREIGN KEY (`Comp_Job_ID`) REFERENCES `company_job` (`Comp_Job_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Rating_ID` FOREIGN KEY (`Rating_ID`) REFERENCES `ratings` (`Rating_ID`) ON DELETE NO ACTION ON UPDATE NO ACTION,
CONSTRAINT `Users_ID` FOREIGN KEY (`Users_ID`) REFERENCES `users` (`Users_id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1
CREATE TABLE `users` (
`Users_id` int(11) NOT NULL AUTO_INCREMENT,
`User_Name` varchar(45) NOT NULL,
`UAddress` varchar(45) NOT NULL,
`UTown` varchar(45) NOT NULL,
`UPostcode` varchar(45) NOT NULL,
`UTelephone` varchar(45) NOT NULL,
`UDOB` varchar(45) NOT NULL,
PRIMARY KEY (`Users_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=latin1
The query needs to look something like this i.e. use this form
SELECT a.Company_name,
f.Job_ID,
f.Job_Name,
b.User_Name,
c.Comments,
c.Reliability,
c.Rating
FROM company a
INNER JOIN Users b
ON a.???? = b.???
Since I dont have your table definitions I cant help you with the JOIN conditions. Show us the tables definition and we would be able to help.
UPDATE:
So based on your table structures you will be looking for something like this:
SELECT *
FROM company cmp
INNER JOIN company_job cmpjb
ON cmp.Company_ID = cmpjb.Company_ID
INNER JOIN jobs jb
ON cmpjb.Job_ID = jb.Job_ID
INNER JOIN usercompjobrating ucmpjbr
ON ucmpjbr.Comp_Job_ID = ucmpjbr.Comp_Job_ID
INNER JOIN users usr
ON usr.Users_id = ucmpjbr.Users_ID
INNER JOIN ratings rat
ON rat.Rating_ID = ucmpjbr.Rating_ID
Note you cannot use the folder table in this join as there are no primary/foreign key relationships to any of the other tables from the folder table.
I would suggest that you carefully dissect this query and let me know if you need to understand the details.
One thing to clarify, what is company_id in table jobs?
select ... (necessary fields to select)
from company c
join company_job cj using (company_id)
join jobs j using (job_id)
join usercompjobrating ucjr using (comp_job_id)
join ratings using (rating_Id)
join users using (users_id)

mysql prevent deleting records that is in used

i got 2 tables. product and order_items which contain all the products that were bought.
so how do i create a relationship in mysql whereby if a product exists in order_items, restrict users from deleting it from product table??
thanks
You can do this with Foreign keys with the InnoDB Engine.
ALTER TABLE order_items ADD FOREIGN KEY (`p_id`) REFERENCES `products` (`p_id`);
The ID on products must be a key (it probably already is the primary key).
If you are not using InnoDB, you cannot enforce this with MySQL, but it must be enforced with your application (check whether a record exists in orders first for example).
So with your tables, you run:
ALTER TABLE `order_item` ADD FOREIGN KEY (`bookid`) REFERENCES `book` (`id`);
You're looking for a foreign key. Specifically look at the "Restrict" option.
http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html
my table structure:
CREATE TABLE `book` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`userid` int(11) NOT NULL,
`title` varchar(100) NOT NULL,
`description` text NOT NULL,
`author` varchar(100) NOT NULL,
`publisher` varchar(100) NOT NULL,
`edition` int(11) NOT NULL,
`isbn` varchar(13) NOT NULL,
`category` varchar(11) NOT NULL,
`datesubmitted` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;
CREATE TABLE `order_item` (
`orderid` int(11) NOT NULL,
`bookid` int(11) NOT NULL,
KEY `Foreign` (`bookid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;