I have a table that contains the details of a game, this table is called match, each match can have n goals, these goals are stored inside the table goal.
Suppose I have the following situation on match:
id = 2564824
home_team_half_time_score = 2
home_team_score = 4
away_team_half_time_score = 0
away_team_score = 0
so this record means that the match is ended 4 - 0 for the home team, what I want to know is: how can I get only the goals scored in the first time? in this case there are 2 goals scored in the first time, and have this id:
id | match_id | result | minute
16092 2564824 1 - 0 15
16093 2564824 2 - 0 43
16094 2564824 3 - 0 63
16095 2564824 4 - 0 78
I just need to get the minute field of each goal, how can I setup the query?
SCHEMA
CREATE TABLE IF NOT EXISTS `swp`.`match` (
`id` INT NOT NULL,
`round_id` INT NULL,
`datetime` DATETIME NULL,
`status` INT NULL,
`gameweek` INT NULL,
`home_team_id` INT NULL,
`home_team_half_time_score` INT NULL,
`home_team_score` INT NULL,
`home_extra_time` INT NULL,
`home_penalties` INT NULL,
`away_team_id` INT NULL,
`away_team_half_time_score` INT NULL,
`away_team_score` INT NULL,
`away_extra_time` INT NULL,
`away_penalties` INT NULL,
`venue_id` INT NULL,
`venue_attendance` INT NULL,
`aggregate_match_id` INT NULL,
PRIMARY KEY (`id`),
INDEX `home_team_id_idx` (`home_team_id` ASC),
INDEX `away_team_id_idx` (`away_team_id` ASC),
INDEX `venue_id_idx` (`venue_id` ASC),
INDEX `match_status_id_idx` (`status` ASC),
INDEX `FK_competition_rounds_match_round_id_idx` (`round_id` ASC),
INDEX `FK_match_match_aggregate_match_id_idx` (`aggregate_match_id` ASC),
CONSTRAINT `FK_team_match_home_team_id`
FOREIGN KEY (`home_team_id`)
REFERENCES `swp`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_team_match_away_team_id`
FOREIGN KEY (`away_team_id`)
REFERENCES `swp`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_venue_match_venue_id`
FOREIGN KEY (`venue_id`)
REFERENCES `swp`.`venue` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_match_status_match_status_id`
FOREIGN KEY (`status`)
REFERENCES `swp`.`match_status` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_rounds_match_round_id`
FOREIGN KEY (`round_id`)
REFERENCES `swp`.`competition_rounds` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_match_match_aggregate_match_id`
FOREIGN KEY (`aggregate_match_id`)
REFERENCES `swp`.`match` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Thanks for any help.
CREATE TABLE IF NOT EXISTS `swp`.`goal` (
`id` INT NOT NULL AUTO_INCREMENT,
`team_id` INT NOT NULL COMMENT 'Team that has scored.',
`player_marker_id` INT NOT NULL,
`player_assist_id` INT NULL,
`match_id` INT NOT NULL,
`minute` VARCHAR(45) NOT NULL,
`result` VARCHAR(45) NULL,
`type` INT NOT NULL COMMENT 'All the status that a goal can assume.',
INDEX `player_marker_id_idx` (`player_marker_id` ASC),
INDEX `player_assist_id_idx` (`player_assist_id` ASC),
INDEX `match_id_idx` (`match_id` ASC),
PRIMARY KEY (`id`),
INDEX `FK_goal_type_goal_goal_type_id_idx` (`type` ASC),
INDEX `FK_team_goal_team_id_idx` (`team_id` ASC),
CONSTRAINT `FK_player_goal_player_marker_id`
FOREIGN KEY (`player_marker_id`)
REFERENCES `swp`.`player` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_player_goal_player_assist_id`
FOREIGN KEY (`player_assist_id`)
REFERENCES `swp`.`player` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_match_goal_match_id`
FOREIGN KEY (`match_id`)
REFERENCES `swp`.`match` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_goal_type_goal_goal_type_id`
FOREIGN KEY (`type`)
REFERENCES `swp`.`goal_type` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_team_goal_team_id`
FOREIGN KEY (`team_id`)
REFERENCES `swp`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
UPDATE
actual query:
$query = "SELECT m.*,
t.name AS team_name,
t.id AS team_id,
l.position AS team_rank,
COUNT(CASE WHEN g.type = 5 THEN 1 END) AS failed_to_score,
FROM `match` m
LEFT JOIN goal g ON m.id = g.match_id
LEFT JOIN team t ON t.id = :team_id
LEFT JOIN league_ranking l ON l.team_id = :team_id AND l.round_id = :round_id
WHERE m.round_id = :round_id
AND m.status = 5 ";
SELECT minute, result FROM goal WHERE (CAST(minute AS UNSIGNED)<=45 OR minute like '45%') AND match_id='2564824'
if this is your starting point:
id | match_id | result | minute
16092 2564824 1 - 0 15
16093 2564824 2 - 0 43
16094 2564824 3 - 0 63
16095 2564824 4 - 0 78
If this is indeed your expected results then you have to show the input data to get this result
UNTESTED
SELECT m.*,
t.name AS team_name,
t.id AS team_id,
l.position AS team_rank,
COUNT(CASE WHEN g.type = 5 THEN 1 END) AS failed_to_score,
g.minute
FROM `match` m
LEFT JOIN goal g ON m.id = g.match_id
LEFT JOIN team t ON t.id = :team_id
LEFT JOIN league_ranking l ON l.team_id = :team_id AND l.round_id = :round_id
WHERE m.round_id = :round_id
AND m.status = 5 "
AND (CAST(minute AS UNSIGNED)<=45 OR minute like '45%');
This integrated query will stop the analysis of each match to the first half. I'd keep the two queries as separate
Related
I have a database table in mysql that store types like "temperature" , "oxygen_saturation" , "heart_rate" , "systolic_pressure" , "diastolic_pressure".
However, for a given checkup_id, some types may not stored. Those I want to show them as N/A.
My table is the following:
CREATE TABLE `exam` (
`id` int NOT NULL AUTO_INCREMENT,
`checkup_id` int NOT NULL,
`type` varchar(100) NOT NULL,
`result` longtext NOT NULL,
`combined_exam_id` int NOT NULL DEFAULT '-1',
`status` tinyint NOT NULL DEFAULT '1',
`version_id` int NOT NULL,
PRIMARY KEY (`id`,`version_id`),
UNIQUE KEY `exam_id` (`id`,`version_id`) /*!80000 INVISIBLE */,
KEY `checkup_idx` (`checkup_id`) /*!80000 INVISIBLE */,
KEY `version_id_fk_exam_idx` (`version_id`),
CONSTRAINT `exam_ibfk_1` FOREIGN KEY (`checkup_id`) REFERENCES `endorse_checkup` (`id`),
CONSTRAINT `version_id_fk_exam` FOREIGN KEY (`version_id`) REFERENCES `ps_versioning` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=65 DEFAULT CHARSET=utf8;
I have the following select statement:
SELECT end_up.id as checkup_id,
end_e.type,
end_e.result,
FROM endorse_exam as end_e
left JOIN endorse_checkup as end_up on end_up.id = end_e.checkup_id
left JOIN ps_versioning as v ON v.id = end_e.version_id
left JOIN u_users as u ON u.user_id = v.user_id
WHERE end_up.patient_id = 50 AND v.id <= (SELECT IF(164 > -1, 164, max(v.id))) and checkup_id = 25;
Note: I put 164 value by hand, but actually it comes through an API.
Using the SQL code above, I get a result like
However, I want to create a query to get info like:
I'm trying to return all the country that have football matches which play in a specific date. The data are defined in the following tables:
competition
id | country_id | name
50 1 Premier League
competition_seasons
id | competition_id | name
70 50 2019
competition_rounds
id | season_id | name
58 70 Regular Season
match
id | round_id | home | away | result | datetime
44 58 22 87 1 - 0 2019-03-16:00:00
There are different competitions stored in the competition table, and then each competition can have multiple season which are stored in the competition_seasons. A season can also have different competition rounds, these are stored in competition_rounds.
All the matches are stored in the match table and are grouped for the round_id.
I wrote this method for the API:
$app->get('/country/get_countries/{date}', function (Request $request, Response $response, array $args)
{
$start_date = $args["date"] . " 00:00";
$end_date = $args["date"] . " 23:59";
$sql = $this->db->query("SELECT n.* FROM country n
LEFT JOIN competition c ON c.country_id = n.id
LEFT JOIN competition_seasons s ON s.competition_id = c.id
LEFT JOIN competition_rounds r ON r.season_id = s.id
LEFT JOIN `match` m ON m.round_id = r.id
WHERE m.datetime BETWEEN '" . $start_date . "' AND '" . $end_date . "'
GROUP BY n.id");
$sql->execute();
$countries = $sql->fetchAll();
return $response->withJson($countries);
});
there are thousands of records organized by id, but the query took about 6, 7 seconds to return all the countries that play in the specified date.
How can I optimize this process?
Performance
UPDATE
I noticed an interesting thing, if I do:
SELECT round_id, DATE("2019-03-18") FROM `match`
the query is really fast, so I guess the datetime field is slow down the join part, any idea about that?
Table Structure
CREATE TABLE IF NOT EXISTS `swp`.`competition` (
`id` INT NOT NULL,
`country_id` INT NULL,
`name` VARCHAR(255) NULL,
`category` INT NULL,
PRIMARY KEY (`id`),
INDEX `id_idx` (`country_id` ASC),
INDEX `FK_competition_types_competition_type_id_idx` (`category` ASC),
CONSTRAINT `FK_country_competition_country_id`
FOREIGN KEY (`country_id`)
REFERENCES `swp`.`country` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_categories_competition_category_id`
FOREIGN KEY (`category`)
REFERENCES `swp`.`competition_categories` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `swp`.`competition_seasons` (
`id` INT NOT NULL AUTO_INCREMENT,
`competition_id` INT NOT NULL,
`season_id` INT NULL,
`name` VARCHAR(45) NOT NULL,
`update_at` DATETIME NULL,
PRIMARY KEY (`id`),
INDEX `FK_competition_competition_seasons_competition_id_idx` (`competition_id` ASC),
CONSTRAINT `FK_competition_competition_seasons_competition_id`
FOREIGN KEY (`competition_id`)
REFERENCES `swp`.`competition` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `swp`.`competition_rounds` (
`id` INT NOT NULL AUTO_INCREMENT,
`round_id` INT NULL,
`season_id` INT NOT NULL,
`name` VARCHAR(255) NULL,
PRIMARY KEY (`id`),
INDEX `FK_competition_seasons_competition_rounds_season_id_idx` (`season_id` ASC),
CONSTRAINT `FK_competition_seasons_competition_rounds_season_id`
FOREIGN KEY (`season_id`)
REFERENCES `swp`.`competition_seasons` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
-- -----------------------------------------------------
-- Table `swp`.`match`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `swp`.`match` (
`id` INT NOT NULL,
`round_id` INT NOT NULL,
`group_id` INT NULL,
`datetime` DATETIME NULL,
`status` INT NULL,
`gameweek` INT NULL,
`home_team_id` INT NULL,
`home_team_half_time_score` INT NULL,
`home_team_score` INT NULL,
`home_extra_time` INT NULL,
`home_penalties` INT NULL,
`away_team_id` INT NULL,
`away_team_half_time_score` INT NULL,
`away_team_score` INT NULL,
`away_extra_time` INT NULL,
`away_penalties` INT NULL,
`venue_id` INT NULL,
`venue_attendance` INT NULL,
`aggregate_match_id` INT NULL,
PRIMARY KEY (`id`),
INDEX `home_team_id_idx` (`home_team_id` ASC),
INDEX `away_team_id_idx` (`away_team_id` ASC),
INDEX `venue_id_idx` (`venue_id` ASC),
INDEX `match_status_id_idx` (`status` ASC),
INDEX `FK_competition_rounds_match_round_id_idx` (`round_id` ASC),
INDEX `FK_match_match_aggregate_match_id_idx` (`aggregate_match_id` ASC),
INDEX `FK_competition_groups_match_group_id_idx` (`group_id` ASC),
CONSTRAINT `FK_team_match_home_team_id`
FOREIGN KEY (`home_team_id`)
REFERENCES `swp`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_team_match_away_team_id`
FOREIGN KEY (`away_team_id`)
REFERENCES `swp`.`team` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_venue_match_venue_id`
FOREIGN KEY (`venue_id`)
REFERENCES `swp`.`venue` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_match_status_match_status_id`
FOREIGN KEY (`status`)
REFERENCES `swp`.`match_status` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_rounds_match_round_id`
FOREIGN KEY (`round_id`)
REFERENCES `swp`.`competition_rounds` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_match_match_aggregate_match_id`
FOREIGN KEY (`aggregate_match_id`)
REFERENCES `swp`.`match` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `FK_competition_groups_match_group_id`
FOREIGN KEY (`group_id`)
REFERENCES `swp`.`competition_groups` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
First, write the query as:
SELECT n.*
FROM country n JOIN
competition c
ON c.country_id = n.id JOIN
competition_seasons s
ON s.competition_id = c.id JOIN
competition_rounds r
ON r.season_id = s.id JOIN
`match` m
ON m.round_id = r.id
WHERE m.datetime >= ? AND
m.datetime < ?
GROUP BY n.id;
The changes here are relatively minor and will not affect performance. But they are important:
JOIN instead of LEFT JOIN, because you require that the conditions match.
Parameters for the date rather than munging the query string, because this is a good idea.
>= and < for the comparison, because this works with both dates and date times. You will need to add 1 day to the end date -- but leave off the time component.
Then, for performance, you want indexes:
match(datetime, round_id)
competition_rounds(id, season_id)
competition_seasons(id, competition_id)
competition(id, country_id)
country(id)
Actually, the first is the most important. The last four are not needed if the respective id columns are declared as primary keys.
With LEFT JOIN, the query can only be executed top-bottom, meaning the last table is scanned for every product of entries in the before tables. Also, using LEFT JOIN and GROUP BY without any aggregate makes no sense, because it will always return all country ids. This having said, I would rewrite it like this:
SELECT DISTINCT
c.country_id
FROM
competition c,
WHERE
EXISTS (
SELECT
*
FROM
competition_seasons s,
competition_rounds r,
`match` m
WHERE
s.competition_id = c.id
AND r.season_id = s.id
AND m.round_id = r.id
AND m.datetime BETWEEN ...
)
This will be correctly optimized by all RDB's I know of.
Note, an 2-column index on (match.datetime, match.round_id) - in this order, will make a huge performance impact. Or is write speed is a concern, at least a single column index on (match.datetime) would be recommended.
Important note about indexes on strings: String comparison is always quirky in RDBs. Make sure you use a binary collation for the datetime column or use native DATETIME format. Various RDBs may fail to use indexes on case-insensitive columns.
Note I removed the join on n - that just add another PK lookup to check that the country still exists in the countries table. You can add it back in if you don't have any ON DELETE CASCADE or other kind of constraint that ensures data consistency, like this:
SELECT DISTINCT
n.id
FROM
country n
WHERE
EXISTS (
SELECT
*
FROM
competition c,
competition_seasons s,
competition_rounds r,
`match` m
WHERE
c.country_id=n.id
AND s.competition_id = c.id
AND r.season_id = s.id
AND m.round_id = r.id
AND m.datetime BETWEEN ...
)
I have a MySQL DB. Acquired data are stored in raw_data_headers, raw_data_rows and raw_data_row_details table.
raw_data_row_details has a foreign key that reference raw_data_rows.ID, the same for raw_data_rows and raw_data_headers.
In raw_data_headers are stored data headers, in raw_data_rows are stored every stage of acquisition program and in raw_data_row_details are stored details for each stage of acquisition program.
This is the query:
SELECT
q1.ProcessTypeID,
q1.TestTypeID,
q1.ComponentID,
q1.TestResultID,
COUNT(*) AS Counter
FROM (
SELECT
raw_data_headers.batch_id AS BatchID,
raw_data_test_outputs.test_output_type_id AS TestOutputTypeID,
raw_data_test_types.process_type_id AS ProcessTypeID,
raw_data_test_types.ID AS TestTypeID,
raw_data_row_details.component_id AS ComponentID,
raw_data_test_results.ID AS TestResultID
FROM raw_data_row_details
INNER JOIN raw_data_rows ON raw_data_rows.ID = raw_data_row_details.row_id
INNER JOIN raw_data_headers ON raw_data_headers.ID = raw_data_rows.header_id
INNER JOIN raw_data_test_results ON raw_data_test_results.ID = raw_data_row_details.Value
INNER JOIN raw_data_test_outputs ON raw_data_test_outputs.ID = raw_data_row_details.test_output_id
INNER JOIN raw_data_test_types ON raw_data_test_types.ID = raw_data_test_outputs.test_type_id
HAVING TestOutputTypeID = 2 AND BatchID = 1
) AS q1
GROUP BY q1.ProcessTypeID, q1.TestTypeID, q1.ComponentID, q1.TestResultID
raw_data_headers has 989'180 entries, row_data_rows has 2'967'540 entries and raw_data_row_details has 13'848'520 entries.
The subquery q1 take about 3 minutes, but final query takes about 25 minutes. I think that the point is in the GROUP BY.
How can I improve performance?
EDIT 1:
SELECT
gnuhmi.raw_data_test_types.process_type_id AS ProcessTypeID,
gnuhmi.raw_data_test_types.ID AS TestTypeID,
gnuhmi.raw_data_row_details.component_id AS ComponentID,
gnuhmi.raw_data_test_results.ID AS TestResultID,
COUNT(*) AS Counter
FROM gnuhmi.raw_data_row_details
INNER JOIN gnuhmi.raw_data_rows ON gnuhmi.raw_data_rows.ID = gnuhmi.raw_data_row_details.row_id
INNER JOIN gnuhmi.raw_data_headers ON gnuhmi.raw_data_headers.ID = gnuhmi.raw_data_rows.header_id
INNER JOIN gnuhmi.raw_data_test_results ON gnuhmi.raw_data_test_results.ID = gnuhmi.raw_data_row_details.Value
INNER JOIN gnuhmi.raw_data_test_outputs ON gnuhmi.raw_data_test_outputs.ID = gnuhmi.raw_data_row_details.test_output_id
INNER JOIN gnuhmi.raw_data_test_types ON gnuhmi.raw_data_test_types.ID = gnuhmi.raw_data_test_outputs.test_type_id
WHERE gnuhmi.raw_data_test_outputs.test_output_type_id = 2 AND gnuhmi.raw_data_headers.batch_id = 1
GROUP BY
gnuhmi.raw_data_test_results.ID,
gnuhmi.raw_data_row_details.component_id,
gnuhmi.raw_data_test_types.ID,
gnuhmi.raw_data_test_types.process_type_id
This is the new query, without subquery and WHERE. This increased performance (thanks #Yogesh Sharma).
this is raw_data_headers structure:
CREATE TABLE `raw_data_headers` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Univocal record key',
`ProductID` int(11) NOT NULL COMMENT 'Product numeric ID',
`Datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Univocal record creation date',
`batch_id` int(11) DEFAULT NULL COMMENT 'Univocal batch key',
`RecipeName` varchar(80) DEFAULT NULL COMMENT 'Used recipe name',
`RecipeVersion` smallint(6) DEFAULT NULL COMMENT 'Used recipe version',
`process_result_id` smallint(6) DEFAULT NULL COMMENT 'Process result key',
`invalidated` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'invalidation after counters reset',
PRIMARY KEY (`ID`),
KEY `FK_raw_data_headers_batches_ID` (`batch_id`),
KEY `FK_raw_data_headers_process_re` (`process_result_id`),
CONSTRAINT `FK_raw_data_headers_batches_ID` FOREIGN KEY (`batch_id`) REFERENCES `batches` (`ID`) ON UPDATE CASCADE,
CONSTRAINT `FK_raw_data_headers_process_re` FOREIGN KEY (`process_result_id`) REFERENCES `process_result` (`ID`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Stores raw data headers'
This the raw_dato_rows:
CREATE TABLE `raw_data_rows` (
`ID` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'Univocal record key',
`Datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Univocal record creation date',
`header_id` int(11) unsigned NOT NULL COMMENT 'Univocal raw data header key',
`process_type_id` smallint(6) NOT NULL COMMENT 'Univocal process type key',
`process_result_id` smallint(6) NOT NULL COMMENT 'Univocal process result key',
PRIMARY KEY (`ID`),
KEY `FK_raw_data_rows_header_id` (`header_id`),
KEY `FK_raw_data_rows_process_resu2` (`process_result_id`),
KEY `FK_raw_data_rows_process_resul` (`process_type_id`),
CONSTRAINT `FK_raw_data_rows_header_id` FOREIGN KEY (`header_id`) REFERENCES `raw_data_headers` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK_raw_data_rows_process_resu2` FOREIGN KEY (`process_result_id`) REFERENCES `process_result` (`ID`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `FK_raw_data_rows_process_resul` FOREIGN KEY (`process_type_id`) REFERENCES `process_types` (`ID`) ON DELETE NO ACTION ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=2967541 DEFAULT CHARSET=utf8 COMMENT='Stores row data rows'
and finally this is the raw_data_row_details one:
CREATE TABLE `raw_data_row_details` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Univocal row detail key',
`row_id` int(11) unsigned NOT NULL COMMENT 'Univocal row key',
`test_output_id` int(11) NOT NULL COMMENT 'Univocal test output key',
`component_id` int(11) NOT NULL COMMENT 'The component that take the measurement',
`Value` double NOT NULL COMMENT 'Output value',
PRIMARY KEY (`ID`),
KEY `FK_raw_data_row_details_row_id` (`row_id`),
KEY `FK_raw_data_rows_raw_data_test_outputs_ID` (`test_output_id`),
KEY `raw_data_row_details_components_FK` (`component_id`),
CONSTRAINT `FK_raw_data_row_details_row_id` FOREIGN KEY (`row_id`) REFERENCES `raw_data_rows` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `FK_raw_data_rows_raw_data_test_outputs_ID` FOREIGN KEY (`test_output_id`) REFERENCES `raw_data_test_outputs` (`ID`) ON UPDATE CASCADE,
CONSTRAINT `raw_data_row_details_components_FK` FOREIGN KEY (`component_id`) REFERENCES `components` (`ID`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=13848521 DEFAULT CHARSET=utf8 COMMENT='Stores raw data rows details'
You don't need to use subquery, just use where clause with group by :
SELECT raw_data_test_types.process_type_id AS ProcessTypeID,
raw_data_test_types.ID AS TestTypeID,
raw_data_row_details.component_id AS ComponentID,
raw_data_test_results.ID AS TestResultID, COUNT(*) AS Counter
FROM raw_data_row_details INNER JOIN
raw_data_rows
ON raw_data_rows.ID = raw_data_row_details.row_id INNER JOIN
raw_data_headers
ON raw_data_headers.ID = raw_data_rows.header_id INNER JOIN
raw_data_test_results
ON raw_data_test_results.ID = raw_data_row_details.Value INNER JOIN
raw_data_test_outputs
ON raw_data_test_outputs.ID = raw_data_row_details.test_output_id INNER JOIN
raw_data_test_types
ON raw_data_test_types.ID = raw_data_test_outputs.test_type_id
WHERE raw_data_headers.batch_id = 1 AND raw_data_test_outputs.test_output_type = 2
GROUP BY raw_data_test_types.process_type_id, raw_data_test_types.ID,
raw_data_row_details.component_id, raw_data_test_results.ID;
Add indexes. TestOutputTypeID and BatchID need to be covered and probably are not.
To see what's currently going on, use EXPLAIN in the MySQL console. You will probably see an indication that a full table scan is happening i.e. the join type is marked as ALL.
It's often the case that the query optimiser will use the same execution plan for different queries e.g. by expanding the subquery as if you hadn't used it. Only EXPLAIN will show you what's what.
Here's the docs on how to interpret the EXPLAIN output: https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
HAVING TestOutputTypeID = 2 AND BatchID = 1
Change that from HAVING to WHERE, and have indexes in each of those columns.
Also have these indexes:
raw_data_row_details: (row_id)
raw_data_rows: (header_id)
raw_data_row_details: (test_output_id)
raw_data_test_outputs: (test_type_id)
Get rid of raw_data_ from the table names; it just clutters the queries.
If those do not help enough, please provide EXPLAIN SELECT ... and SHOW CREATE TABLE.
i am working on two tables,
CREATE TABLE IF NOT EXISTS `users` (
`userid` INT NOT NULL AUTO_INCREMENT ,
`fname` VARCHAR(45) NOT NULL ,
`lname` VARCHAR(45) NOT NULL ,
`usernick` VARCHAR(45) NOT NULL ,
PRIMARY KEY (`userid`) ,
UNIQUE INDEX `usernick_UNIQUE` (`usernick` ASC) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `messages` (
`messageid` INT NOT NULL AUTO_INCREMENT ,
`sendid` INT NOT NULL ,
`recid` INT NOT NULL ,
`message` VARCHAR(1000) NOT NULL ,
`date` TIMESTAMP NULL ,
PRIMARY KEY (`messageid`) ,
INDEX `sender_fk_idx` (`sendid` ASC) ,
INDEX `reciever_fk_idx` (`recid` ASC) ,
CONSTRAINT `sender_fk`
FOREIGN KEY (`sendid` )
REFERENCES `users` (`userid` )
ON DELETE CASCADE
ON UPDATE CASCADE,
CONSTRAINT `reciever_fk`
FOREIGN KEY (`recid` )
REFERENCES `users` (`userid` )
ON DELETE CASCADE
ON UPDATE CASCADE)
ENGINE = InnoDB;
and want a list of user on basis if their last sent message. Eg.
select U.fname,U.lname,U.usernick from messages as M natural join users as U where M.sendid = U.userid and M.recid={$_SESSION['user_id']} group by U.usernick ORDER BY M.date DESC
EXAMPLE:
name msg sent to "RON" on
Alpha 17 aug
Beta 18 aug
Alpha 19 aug
Gamma 20 aug
SO i want a list like,
gamma (last msg on 20)
alpha (last msg on 18)
beta (last msg on 19)
SEE LINK http://sqlfiddle.com/#!2/9dca2/2/0
You almost have it. You just need max(m.date) in the order by clause. Otherwise, an arbitrary date is chosen:
select U.fname,U.lname,U.usernick
from messages as M join
users as U
on M.sendid = U.userid
where M.recid={$_SESSION['user_id']}
group by U.usernick
ORDER BY max(M.date) DESC
I also fixed the join syntax. It is best to avoid natural joins -- that is, be explicit about the join condition. You do this anyway, so I switched the condition to an on clause and the natural join to a join.
I am developing a website like any other social networking site using mysql.
I wish it give people suggestion to my users, and I have implemented this functionality in my application, but It is working very slow. this process take 2-3 seconds to fetch result from server. It has all the necessary indexes, relations on table. I have used EXPLAIN command to understand it, but I got nothing problematic in it.
I can't understand what is the basic problem in it. Please help me.
here is my table structure :
Table : UserMaster
~~~~~~~~~~~~~~~~~~
CREATE TABLE `UserMaster` (
`UserID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`UserName` varchar(20) DEFAULT NULL,
`EMailID` varchar(50) DEFAULT NULL,
`FirstName` varchar(20) NOT NULL,
`LastName` varchar(20) NOT NULL,
`CityID` mediumint(8) unsigned DEFAULT NULL,
PRIMARY KEY (`UserID`),
UNIQUE KEY `UX_UserMaster_UserName` (`UserName`),
UNIQUE KEY `UX_UserMaster_EMailID` (`EMailID`),
KEY `FK_UserMaster_CityMst_CityID_idx` (`CityID`),
KEY `FK_UserMaster_CountryMst_CountryID_idx` (`CountryID`),
CONSTRAINT `FK_UserMaster_CityMst_CityID`
FOREIGN KEY (`CityID`) REFERENCES `CityMst` (`CityID`) ON DELETE NO ACTION,
CONSTRAINT `FK_UserMaster_CountryMst_CountryID` FOREIGN KEY CountryID REFERENCES CountryMst (CountryID) ON DELETE NO ACTION ON UPDATE CASCADE
)
ENGINE=InnoDB AUTO_INCREMENT=19722 DEFAULT CHARSET=utf8$$
Table : UserFriends
~~~~~~~~~~~~~~~~~~~
CREATE TABLE `UserFriends` (
`FriendID` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`UserID` mediumint(8) unsigned NOT NULL,
`UserID2` mediumint(8) unsigned NOT NULL,
`RequestDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`Status` tinyint(3) unsigned NOT NULL DEFAULT '2',
`ApprovalDate` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`FriendID`),
UNIQUE KEY `UX_UserFriends_UserID_UserID2` (`UserID`,`UserID2`),
KEY `IX_UserFriens_UserID_ApprovalStatus` (`UserID`,`ApprovalStatus`,`UserID2`,`FriendID`,`RequestDate`,`ApprovalDate`),
KEY `FK_UserFriends_UserMaster_UserID_idx` (`UserID`),
KEY `FK_UserFriends_UserMaster_UserID2_idx` (`UserID2`),
CONSTRAINT `FK_UserFriends_UserMaster_UserID` FOREIGN KEY (`UserID`) REFERENCES `UserMaster` (`UserID`) ON DELETE NO ACTION ON UPDATE CASCADE,
CONSTRAINT `FK_UserFriends_UserMaster_UserID2` FOREIGN KEY (`UserID2`) REFERENCES `UserMaster` (`UserID`) ON DELETE NO ACTION ON UPDATE CASCADE
)
ENGINE=InnoDB AUTO_INCREMENT=50825 DEFAULT CHARSET=utf8$$
UserID & UserID2 both fields are linked with UserMaster.UserID
Here is my select query :
~~~~~~~~~~~~~~~~~~~~~~~~~
SELECT
upm.UserID,
upm.UserName,
upm.FirstName,
COALESCE(mf.TotMutualFriends,0) TotMutualFriends
FROM UserMaster upm
LEFT JOIN CityMst ct on ct.CityID = upm.CityID
LEFT JOIN StateMst st on st.StateID = ct.StateID
LEFT JOIN (
SELECT uf.UserID, COUNT(1) TotMutualFriends
FROM (
SELECT uf.UserID, uf.UserID2, uf.ApprovalStatus
FROM UserFriends uf
UNION ALL
SELECT uf.UserID2 UserID, uf.UserID UserID2, uf.ApprovalStatus
FROM UserFriends uf
) uf
INNER JOIN (
SELECT IF(uf.UserID = 1, uf.UserID2, uf.UserID) UserID2
FROM UserFriends uf
WHERE (uf.UserID = 1 OR uf.UserID2 = 1)
AND uf.ApprovalStatus = 1
) uf1 on uf1.UserID2 = uf.UserID2
WHERE uf.ApprovalStatus = 1
GROUP BY uf.UserID
) mf on mf.UserID = upm.UserID
LEFT JOIN (
SELECT DISTINCT usar.UserID2
FROM UserSuggAutoRejct usar
WHERE usar.UserID = 1
UNION
SELECT IF(uf.UserID = 1, uf.UserID2, uf.UserID) UserID2
FROM UserFriends uf
WHERE (uf.UserID = 1 OR uf.UserID2 = 1)
) usar ON usar.UserID2 = upm.UserID
WHERE upm.UserStatus IN(10,11)
AND upm.UserID <> 1
AND upm.UserID NOT IN (1221,2191)
AND usar.UserID2 IS NULL
ORDER BY
(CASE WHEN COALESCE(mf.TotMutualFriends,0) > 0 THEN 0 ELSE 1 END),
(CASE WHEN COALESCE(mf.TotMutualFriends,0) > 0 THEN RAND() ELSE NULL END),
(CASE upm.CityID WHEN 1 THEN 0 ELSE 1 END),
(CASE upm.CityID WHEN 1 THEN RAND() ELSE NULL END),
(CASE ct.StateID WHEN 1 THEN 0 ELSE 1 END),
(CASE ct.StateID WHEN 1 THEN RAND() ELSE NULL END),
(CASE st.CountryID WHEN 91 THEN 0 ELSE 1 END),
(CASE st.CountryID WHEN 91 THEN RAND() ELSE NULL END)
LIMIT 10
This is performing very slow. It takes 2-3 seconds to evolute.
relational database might not be relevant for social networking sites.
because joining table is very slow, try using other no-sql databases(NoSql type database).
if u still insist using mysql, then try not to much join in your query.
sorry for my bad english, if any.