MYSQL Join/Index optimization - mysql
I have a query that tries to find all shopping carts containing a set of given packages.
For each package I join the corresponding cartitem table once, because I am only interested in carts containing all given packages.
When I reach more than 15 packages(joins) the query performance rapidly drops.
I have two indeces on the corresponding foreign columns and am aware that mysql uses only one of them. When I add an index over the 2 columns(cartitem_package_id,cartitem_cart_id) it works, but is this the only way to solve this situation?
I would like to know why MYSQL suddently stucks in this situation and what may be the mysql internal problem, because I do not see any deeper problem with this definition and query? Does that may be an issue with the query optimizer and can I do something(e.g. adding brackets) to support or force a specific query execution? Or has anyone a different approach here, using another query?
The query looks something like this:
SELECT cart_id
FROM cart
INNER JOIN cartitem as c1 ON cart_id=c1.cartitem_cart_id AND c1.cartitem_package_id= 7
INNER JOIN cartitem as c2 ON cart_id=c2.cartitem_cart_id AND c2.cartitem_package_id= 8
INNER JOIN cartitem as c3 ON cart_id=c3.cartitem_cart_id AND c3.cartitem_package_id= 9
INNER JOIN cartitem as c4 ON cart_id=c4.cartitem_cart_id AND c4.cartitem_package_id= 10
INNER JOIN cartitem as c5 ON cart_id=c5.cartitem_cart_id AND c5.cartitem_package_id= 11
INNER JOIN cartitem as c6 ON cart_id=c6.cartitem_cart_id AND c6.cartitem_package_id= 12
INNER JOIN cartitem as c7 ON cart_id=c7.cartitem_cart_id AND c7.cartitem_package_id= 13
INNER JOIN cartitem as c8 ON cart_id=c8.cartitem_cart_id AND c8.cartitem_package_id= 14
INNER JOIN cartitem as c9 ON cart_id=c9.cartitem_cart_id AND c9.cartitem_package_id= 15
INNER JOIN cartitem as c10 ON cart_id=c10.cartitem_cart_id AND c10.cartitem_package_id= 16
INNER JOIN cartitem as c11 ON cart_id=c11.cartitem_cart_id AND c11.cartitem_package_id= 17
INNER JOIN cartitem as c12 ON cart_id=c12.cartitem_cart_id AND c12.cartitem_package_id= 18
INNER JOIN cartitem as c13 ON cart_id=c13.cartitem_cart_id AND c13.cartitem_package_id= 19
INNER JOIN cartitem as c14 ON cart_id=c14.cartitem_cart_id AND c14.cartitem_package_id= 20
INNER JOIN cartitem as c15 ON cart_id=c15.cartitem_cart_id AND c15.cartitem_package_id= 21
INNER JOIN cartitem as c16 ON cart_id=c16.cartitem_cart_id AND c16.cartitem_package_id= 22
INNER JOIN cartitem as c17 ON cart_id=c17.cartitem_cart_id AND c17.cartitem_package_id= 23
Output:
No result.
Consider the following sample structure:
CREATE TABLE IF NOT EXISTS `cart` (
`cart_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cart_state` smallint(20) DEFAULT NULL,
PRIMARY KEY (`cart_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=80 ;
INSERT INTO `cart` (`cart_id`, `cart_state`) VALUES
(1, 0),(2, 5),(3, 0),(4, 0),(5, 0),(6, 0),(7, 0),(8, 0),(9, 0),(10, 0),(11, 0),(12, 0),(13, 0),(14, 5),(15, 5),(16, 10),(17, 0),(18, 10),(19, 40),(20, 10),(21, 5),(22, 0),(23, 10),(24, 10),(25, 0),(26, 10),(27, 5),(28, 5),(29, 0),(30, 5),(31, 0),(32, 0),(33, 0),(34, 0),(35, 0),(36, 0),(37, 0),(38, 0),(39, 0),(40, 0),(41, 0),(42, 0),(43, 0),(44, 0),(45, 40),(46, 0),(47, 0),(48, 1),(49, 0),(50, 5),(51, 0),(52, 0),(53, 5),(54, 5),(55, 0),(56, 0),(57, 10),(58, 0),(59, 0),(60, 5),(61, 0),(62, 0),(63, 10),(64, 0),(65, 5),(66, 5),(67, 10),(68, 10),(69, 0),(70, 0),(71, 10),(72, 0),(73, 10),(74, 0),(75, 10),(76, 0),(77, 10),(78, 0),(79, 10);
CREATE TABLE IF NOT EXISTS `cartitem` (
`cartitem_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`cartitem_package_id` int(10) unsigned DEFAULT NULL,
`cartitem_cart_id` int(10) unsigned DEFAULT NULL,
`cartitem_price` decimal(7,2) NOT NULL DEFAULT '0.00',
PRIMARY KEY (`cartitem_id`),
KEY `cartitem_package_id` (`cartitem_package_id`),
KEY `cartitem_cart_id` (`cartitem_cart_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=89 ;
INSERT INTO `cartitem` (`cartitem_id`, `cartitem_package_id`, `cartitem_cart_id`, `cartitem_price`) VALUES
(1, 4, 2, 200.00),(2, 7, 3, 30.00),(3, 14, 9, 255.00),(4, 14, 9, 255.00),(5, 22, 9, 120.00),(6, 22, 9, 120.00),(7, 13, 13, 300.00),(8, 13, 13, 300.00),(9, 7, 14, 450.00),(10, 13, 14, 250.00),(11, 17, 14, 150.00),(12, 7, 15, 450.00),(13, 13, 15, 250.00),(14, 18, 15, 127.50),(15, 7, 16, 450.00),(16, 17, 16, 150.00),(17, 7, 18, 450.00),(18, 7, 19, 450.00),(19, 17, 19, 150.00),(20, 21, 19, 25.00),(21, 13, 20, 300.00),(22, 7, 21, 550.00),(23, 19, 21, 105.00),(24, 22, 21, 120.00),(25, 17, 22, 150.00),(26, 7, 23, 550.00),(27, 11, 24, 245.00),(31, 7, 26, 450.00),(32, 21, 26, 25.00),(33, 21, 26, 25.00),(34, 22, 26, 120.00),(35, 23, 26, 120.00),(36, 10, 27, 382.50),(37, 22, 27, 120.00),(38, 13, 27, 250.00),(39, 10, 28, 297.50),(43, 7, 29, 550.00),(41, 20, 28, 82.50),(42, 22, 28, 120.00),(44, 7, 30, 550.00),(46, 22, 30, 120.00),(47, 23, 30, 120.00),(48, 21, 18, 25.00),(49, 21, 19, 25.00),(50, 17, 37, 150.00),(51, 17, 37, 150.00),(52, 21, 37, 25.00),(53, 21, 37, 25.00),(54, 4, 45, 1.20),(55, 6, 45, 0.00),(56, 7, 47, 450.00),(57, 4, 50, 200.00),(58, 13, 52, 250.00),(59, 13, 19, 300.00),(60, 9, 19, 0.00),(61, 17, 53, 150.00),(62, 7, 53, 450.00),(63, 22, 18, 120.00),(64, 7, 16, 450.00),(65, 7, 54, 450.00),(66, 7, 57, 450.00),(67, 17, 57, 150.00),(68, 7, 56, 450.00),(69, 17, 59, 150.00),(70, 7, 60, 450.00),(71, 17, 61, 150.00),(72, 17, 63, 150.00),(73, 21, 65, 25.00),(74, 7, 66, 450.00),(75, 7, 67, 450.00),(76, 11, 68, 385.00),(77, 7, 71, 450.00),(78, 11, 73, 385.00),(79, 13, 73, 300.00),(80, 4, 75, 200.00),(82, 7, 73, 30.00),(83, 18, 73, 127.50),(84, 23, 73, 120.00),(85, 7, 73, 30.00),(86, 10, 77, 382.50),(87, 7, 79, 550.00),(88, 17, 79, 150.00);
The given query was a possible edge case leading to no results in this example.
SELECT cart_id
FROM cart
INNER JOIN cartitem as c1 ON cart_id=c1.cartitem_cart_id AND c1.cartitem_package_id= 7
INNER JOIN cartitem as c3 ON cart_id=c3.cartitem_cart_id AND c3.cartitem_package_id= 9
INNER JOIN cartitem as c4 ON cart_id=c4.cartitem_cart_id AND c4.cartitem_package_id= 13
INNER JOIN cartitem as c5 ON cart_id=c5.cartitem_cart_id AND c5.cartitem_package_id= 17
INNER JOIN cartitem as c6 ON cart_id=c6.cartitem_cart_id AND c6.cartitem_package_id= 21
Output:
cart_id
-------------
19
19
The query should return all carts containing items that are connected to packages(7,9,13,17,21) in this case.
My approach to your problem would be:
SELECT
cart_id
FROM
cart
INNER JOIN
cartitem
ON
cart_id = cartitem_cart_id
WHERE
cartitem_package_id IN (7,9,13,17,21) -- items that got to be in the cart
GROUP BY
cart_id
HAVING
count(distinct cartitem_package_id) = 5 -- number of different packages
;
DEMO with your data
Explanation
The principle is to filter first with the list of the desired values, here your packages. Now count the different packages per cart (GROUP BY cart_id). If this count matches the number of values in your filter list, then every single package must be in this cart.
You can replace the value list of the IN clause with a subselect, if you get those values from a subselect.
You should see that this approach should be easy to adapt to similar needs.
Related
Finding Connection Pairs
Suppose we have a table in mySQL database where fname has a connection to another fname(BB_Connection_name), we would like have a query to find the pair(s) of friends who find connection among themselves. E.g Sidharth and Asim both have each others BBid and BB_Connection_ID I have looked for similar case of father, son and grandson question but in that not each father has a son and thus inner joining them makes things easier for solving. I tried using that but didn't work. Here i need to check BB_Connection_ID for every fname(A) and then corresponding fname has A's BBid as his BB_Connection_ID or not. The pairs which would be chosen, should be like Sidharth<->Asim We need to find the pairs who have their connection ID to each other. ========================================================================== Code for recreation of the table: ----------------------------------------------------------------------------- create table world.bigbb( BBid int not null auto_increment, fname varchar(20) NOT NULL, lname varchar(30), BBdays int not null, No_of_Nom int, BB_rank int not null, BB_Task varchar(10), BB_Connection_ID int, BB_Connection_name varchar(10), primary key (BBid) ); insert into world.bigbb (fname, lname, BBdays, No_of_Nom, BB_rank, BB_Task, BB_Connection_ID, BB_Connection_name) values ('Sidharth', 'Shukla', 40, 4, 2, 'Kitchen', 11, 'Asim'), ('Arhaan', 'Khan', 7, 1, 9, 'Kitchen', 16, 'Rashmi'), ('Vikas', 'Bhau', 7, 1, 8, 'Bedroom', 11, 'Asim'), ('Khesari', 'Bihari', 7, 1, 12, 'Kitchen', 9, 'Paras'), ('Tehseem', 'Poonawala', 7, 1, 11, 'Washroom', 12, 'Khesari'), ('Shehnaaz', 'Gill', 40, 4, 4, 'Washroom', 9, 'Paras'), ('Himanshi', 'Khurana', 7, 0, 7, 'Bedroom', 8, 'Shefali'), ('Shefali', 'Zariwala', 7, 1, 10, 'Bedroom', 1, 'Sidharth'), ('Paras', 'Chabra', 40, 3, 1, 'Bathroom', 10, 'Mahira'), ('Mahira', 'Sharma', 40, 4, 5, 'Kitchen', 9, 'Paras'), ('Asim', 'Khan', 40, 3, 3, 'Bathroom', 1, 'Sidharth'), ('Arti', 'Singh', 40, 5, 6, 'Captain', 1, 'Sidharth'), ('Sidharth', 'Dey', 35, 6, 16, 'None', 14, 'Shefali'), ('Shefali', 'Bagga', 38, 5, 15, 'None', 13, 'Sidharth'), ('Abu', 'Fifi', 22, 5, 17, 'None', 11, 'Asim'), ('Rashmi', 'Desai', 38, 5, 13, 'None', 17, 'Debolina'), ('Debolina', 'Bhattacharjee', 38, 5, 14, 'None', 16, 'Rashmi');
One solution would be to self-join the table: select b1.fname name1, b2.fname name2 from bigbb b1 inner join bigbb b2 on b1.BB_Connection_ID = b2.BBid and b2.BB_Connection_ID = b1.BBid and b1.BBid < b2.BBid This will give you one record for each pair, with the record having the smallest BBid in the first column. This demo on DB Fiddle with your sample data returns: name1 | name2 :------- | :------- Sidharth | Asim Paras | Mahira Sidharth | Shefali Rashmi | Debolina
Need mysql query to find total sum as per matched query
I need to find sum of specific columns as per matched some of columns value in database table. Please check mysql table that i use : CREATE TABLE IF NOT EXISTS `plant_production_items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `plant_production_id` int(11) NOT NULL, `materialid` int(11) NOT NULL, `packaging_id` int(11) NOT NULL, `grade_id` int(11) NOT NULL, `slabs` int(11) NOT NULL, PRIMARY KEY (`id`), KEY `material_purchase_id` (`plant_production_id`), KEY `grade_id` (`grade_id`), KEY `packaging_id` (`packaging_id`), KEY `slabs` (`slabs`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=104 ; Value are as under : INSERT INTO `plant_production_items` (`id`, `plant_production_id`, `materialid`, `packaging_id`, `grade_id`, `slabs`) VALUES (5, 4, 22, 85, 29, 4444), (6, 5, 22, 14, 25, 3234), (8, 6, 27, 21, 60, 4444), (11, 8, 22, 85, 29, 44444), (19, 7, 22, 84, 29, 434), (75, 10, 26, 0, 51, 1233), (76, 10, 24, 17, 34, 251), (78, 10, 26, 0, 46, 3234), (91, 9, 27, 21, 57, 1000), (92, 9, 27, 21, 57, 2000), (93, 3, 23, 16, 32, 5000), (94, 3, 27, 21, 54, 3233), (101, 3, 27, 21, 0, 700), (103, 3, 29, 27, 0, 6666); I want total sum of 'slabs' columns as per unique value founded in following column : plant_production_id materialid packaging_id grade_id In short we need to find combination of all 4 values of above and need to show total sum of 'slabs' column. For example : there are two records which are same: (91, 9, 27, 21, 57, 1000), (92, 9, 27, 21, 57, 2000), so here i want to get total sum i.e 1000+2000 = 3000 Out put should be all columns with total slabs. It is not required we need to match all above 4 columns. Actually we need to find all total slabs as per total records found same with above 4 column. If still not clear then let me know.
You can use GROUP BY like this: SELECT plant_production_id, materialidm, packaging_id, grade_id, SUM(`slabs`) slabs_sum FROM plant_production_items GROUP BY plant_production_id, materialidm, packaging_id, grade_id; So it gives the sum of the slabs for rows with the same values for columns grouped by.
MySQL - group_concat pulling in additional incorrect data
I'm having trouble with a JOIN and a GROUP_CONCAT. The query is concatenating additional data that should not be associated with the join. Here's my table structure: linkages ID table_name tag_id 1 subcategories 6 2 categories 9 music ID artwork 1 5 2 4 artwork ID url_path 1 /some/file/path 2 /some/file/path And here's my query: SELECT music.*, artwork.url_path AS artwork_url_path, GROUP_CONCAT( linkages.tag_id ) AS tag_ids, GROUP_CONCAT( linkages.table_name ) AS table_name FROM music LEFT JOIN artwork ON artwork.id = music.artwork LEFT JOIN linkages ON music.id = linkages.track_id WHERE music.id IN( '1356', '1357', '719', '169', '170', '171', '805' ) ORDER BY FIELD( music.id, 1356, 1357, 719, 169, 170, 171, 805 ) This is the result of the GROUP_CONCAT : [tag_ids] => 3, 6, 9, 17, 19, 20, 26, 49, 63, 64, 53, 57, 63, 65, 67, 73, 79, 80, 85, 96, 98, 11, 53, 67, 3, 6, 15, 17, 26, 38, 50, 63, 74, 53, 56, 57, 62, 63, 65, 66, 67, 72, 85, 88, 98, 24, 69, 71, 3, 6, 15, 17, 26, 38, 50 The first portion of the result is correct: [tag_ids] => 3, 6, 9, 17, 19, 20, 26, 49, 63, 64, 53, 57, 63, 65, 67, 73, 79, 80, 85, 96, 98, 11, 53, 67 Everything after the correct values seems random and most of the values don't exist in the result in the database, but it's still pulling it in. It seems to repeat a portion of the correct result (3, 6, 15, 17 - the 3, 6, 17 are correct, but 15 shouldn't be there, similar with a bunch of other numbers - 71, etc. I can't use DISTINCT because I need to match up the tag_ids and table_name results as a multidimensional array from the results. Any thoughts as to why? UPDATE: I ended up solving it with the initial push from Gordon. It needed a GROUP_BY clause, otherwise it was putting every results tag id's in each result. The final query ended up becoming this: SET SESSION group_concat_max_len = 1000000; SELECT music.*, artwork.url_path as artwork_url_path, GROUP_CONCAT(linkages.tag_id, ':', linkages.table_name) as tags FROM music LEFT JOIN artwork ON artwork.id = music.artwork LEFT JOIN linkages ON music.id = linkages.track_id WHERE music.id IN('1356', '1357', '719', '169', '170', '171', '805') GROUP BY music.id ORDER BY FIELD(music.id,1356,1357,719,169,170,171,805);
Your join is generating duplicate rows. I would suggest that you fix the root cause of the problem. But, a quick-and-dirty solution is to use group_concat(distinct): GROUP_CONCAT(DISTINCT linkages.tag_id) as tag_ids, GROUP_CONCAT(DISTINCT linkages.table_name) as table_name You can put the columns in a single field using GROUP_CONCAT(): GROUP_CONCAT(DISTINCT linkages.tag_id, ':', linkages.table_name) as tags
Can anyone provide me with some insight into why this query is taking a long time to run?
SELECT PatientID as 'PatientIDIX', claims.ClaimID as 'ClaimIDIX', ClaimThroughDate as 'ClaimThroughDateIX', HCPCCode, ProcedureID FROM `t1`.revenue revenue JOIN `t1`.patient patient ON revenue.ClaimID = patient.ClaimID JOIN `t1`.claims claims ON claims.ClaimID = revenue.ClaimID LEFT JOIN `t1`.procedures procedures ON procedures.ClaimID = revenue.ClaimID WHERE HCPCCode IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) OR ProcCode IN (11, 22, 33, 44, 55, 66, 77, 88, 99, 1010); I was wondering if anyone has some insight into why the above query is taking so long. I believe it is because of the left join. Thanks!
I found a few articles that may help you: http://explainextended.com/2009/08/18/passing-parameters-in-mysql-in-list-vs-temporary-table/ http://www.slideshare.net/techdude/how-to-kill-mysql-performance MYSQL OR vs IN performance Depending on your data, indexing and other factors, the simplest solution may be to use a temp table instead of using the IN statement.
To print the list of user_id from the string list
I have a problem, i have a query that just simply displays the user id in set,for retreieving the user id i am calling the function and it gives me the below list as string SELECT u.user_id FROM user u WHERE u.user_id IN ( '2, 3, 4, 5, 6, 7, 22, 33, 44, 55, 66, 77, 13, 23, 43, 53, 63, 73' ) but when i execute this query it displays only the first user_id ie: 2 and all the user id are present in the database So any help is deeply appreciated
Your code: SELECT u.user_id FROM user u WHERE u.user_id IN ( '2, 3, 4, 5, 6, 7, 22, 33, 44, 55, 66, 77, 13, 23, 43, 53, 63, 73' ) http://forums.mysql.com/read.php?10,217174 Im almost surprised you had any match.. each of the numbers in your in list, need to be individual strings, eg '1','2','3' etc.
Remove single quotes like this and try code again- SELECT u.user_id FROM user u WHERE u.user_id IN ( 2, 3, 4, 5, 6, 7, 22, 33, 44, 55, 66, 77, 13, 23, 43, 53, 63, 73);
Remove the single quotes: IN ( 2, 3, 4, 5, 6, 7, 22, 33, 44, 55, 66, 77, 13, 23, 43, 53, 63, 73 )