How can I reduce execution time of a query - mysql

When I run this query, it takes almost around 30 min to complete. How can I reduce the execution time?
INSERT INTO vfusion.attendance_report_data_2
SELECT
CONCAT(attendance_checkin.userid, UNIX_TIMESTAMP(DATE(IFNULL(attendance_checkin.work_date, 0)))) AS id,
attendance_checkin.userid,
attendance_checkin.work_date,
attendance_checkin.checkintime_data as in_time,
attendance_checkout.checkouttime_data as out_time,
IFNULL(attendance_checkin.work_shift,0) as work_shift
FROM
vfusion.attendance_checkin
INNER JOIN
vfusion.attendance_checkout ON attendance_checkin.userid = attendance_checkout.userid
AND attendance_checkin.work_date = attendance_checkout.work_date
ON DUPLICATE KEY
UPDATE
in_time = in_time,
out_time = out_time,
work_shift = attendance_checkin.work_shift
These are my tables - I have a lot of data in this table
CREATE TABLE attendance_checkout
(
id_attendance_checkout BIGINT(11) NOT NULL,
userid INT(11) DEFAULT NULL,
work_date DATE DEFAULT NULL,
checkouttime_data DATETIME DEFAULT NULL,
work_shift INT(11) DEFAULT NULL,
PRIMARY KEY (id_attendance_checkout)
) ENGINE=INNODB DEFAULT CHARSET=LATIN1;
CREATE TABLE attendance_checkin
(
id_attendance_checkin BIGINT(11) NOT NULL,
userid INT(11) DEFAULT NULL,
work_date DATE DEFAULT NULL,
checkintime_data DATETIME DEFAULT NULL,
work_shift INT(11) DEFAULT NULL,
PRIMARY KEY (id_attendance_checkin)
) ENGINE=INNODB DEFAULT CHARSET=LATIN1;
CREATE TABLE attendance_report_data_2
(
id_attendance_report_data BIGINT(11) NOT NULL,
userid INT(11) NOT NULL DEFAULT '0',
work_date DATE NOT NULL DEFAULT '0000-00-00',
in_time DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
out_time DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
work_shift INT(11) NOT NULL DEFAULT '0',
PRIMARY KEY (id_attendance_report_data , in_time , out_time , work_date , userid , work_shift)
) ENGINE=INNODB DEFAULT CHARSET=LATIN1
I need to run this query randomly but for taking log time I can't run it.
Because it's stuck all other

Create an index for the combination of columns [userid] and [work_date] in table [vfusion.attendance_checkout]
This speeds up the JOIN

Related

MySQL - Fix my poor performing UPDATE?

I have an event which fires periodically to 'abort' some abandoned games (a simple matching server).
This update is proving very (VERY) slow and I'm looking for advice on doing this better.
Problematic Update:
UPDATE user SET skill=skill+
(SELECT count(participant_1) * 25 FROM matches
WHERE score_2 IS NULL
AND score_2_time IS NOT NULL
AND participant_1=user.id
AND score_2_time < (NOW() - INTERVAL 1 HOUR)
AND status=0);
Matches table:
matches CREATE TABLE `matches` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `match_hash` varchar(64) DEFAULT NULL,
 `skill` int(10) unsigned DEFAULT NULL,
 `status` int(10) unsigned DEFAULT NULL,
 `participant_1` int(10) unsigned DEFAULT NULL,
 `score_1` int(10) unsigned DEFAULT NULL,
 `score_1_time` timestamp NULL DEFAULT NULL,
 `participant_1_rematched` tinyint(4) DEFAULT NULL,
 `participant_2` int(10) unsigned DEFAULT NULL,
 `score_2` int(10) unsigned DEFAULT NULL,
 `score_2_time` timestamp NULL DEFAULT NULL,
 `participant_2_rematched` tinyint(4) DEFAULT NULL,
 `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
 `finished_at` timestamp NULL DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=40667 DEFAULT CHARSET=latin1
User table:
user CREATE TABLE `user` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `name` varchar(32) COLLATE utf8_unicode_ci DEFAULT NULL,
 `skill` int(10) unsigned DEFAULT NULL,
 `created` timestamp NOT NULL DEFAULT current_timestamp(),
 PRIMARY KEY (`id`),
 UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1876 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Any guidance is greatly appreciated.
You need more indexes on the matches table, certainly at least participant_1, and whatever else is mentioned in the WHERE clause that helps. Probably participant_1 should be a foreign key into user.id for integrity reasons.
Try this query:
update user a join (SELECT participant_1,count(participant_1) * 25 as count FROM matches
WHERE score_2 IS NULL
AND score_2_time IS NOT NULL
AND score_2_time < (NOW() - INTERVAL 1 HOUR)
AND status=0 group by participant_1) b on a.id=b.participant_1 SET a.skill=a.skill+b.count

MySql - Create view to read from Multiple Tables

I have archived some old line items for invoices that are no longer current but still need to reference them. I think I need to create a VIEW but not really understanding it. Can someone help so I can run a query to pull the invoice and then the total of all the line items assigned (no matter what table the items are in)?
CREATE TABLE `Invoice` (
`Invoice_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`Invoice_CreatedDateTime` DATETIME DEFAULT NULL,
`Invoice_Status` ENUM('Paid','Sent','Unsent','Hold') DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`)
) ENGINE=MYISAM DEFAULT CHARSET=latin1
CREATE TABLE `Invoice_LineItem` (
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
CREATE TABLE `Invoice_LineItem_Archived` (
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MYISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1
Typically I would just run the following query to get the amount due on the invoices
SELECT
Invoice_ID,
Invoice_CreatedDateTime,
Invoice_Status,
(SELECT SUM(LineItem_Amount) AS totAmt FROM Invoice_LineItem WHERE LineItem_InvoiceID=Invoice_ID) AS Invoice_Total
FROM
Invoice
WHERE
Invoice_Status='Sent'
Also how can I select all the line items from both tables in one query?
SELECT
LineItem_ID,
LineItem_ChargeType,
LineItem_Amount
FROM
Invoice_LineItem
WHERE
LineItem_InvoiceID='1234'
You can use the MERGE Storage Engine to create a virtual table that's the union of two real tables:
CREATE TABLE Invoice_LineItem_All
(
`LineItem_ID` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`LineItem_ChargeType` VARCHAR(64) NOT NULL DEFAULT '',
`LineItem_InvoiceID` INT(11) UNSIGNED DEFAULT NULL,
`LineItem_Amount` DECIMAL(11,4) DEFAULT NULL,
`LastUpdatedAt` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
KEY (`LineItem_ID`),
KEY `LastUpdatedAt` (`LastUpdatedAt`),
KEY `LineItem_InvoiceID` (`LineItem_InvoiceID`)
) ENGINE=MERGE UNION=(Invoice_LineItem_Archived, Invoice_LineItem);
You can use UNION :
SELECT a.* FROM a
UNION
SELECT b.* FROM b;
You just need to have the same number and type of column in your different queries.
As far as I remember, you can add test in sub-queries, but I'm not sure you can order on the global result.
http://dev.mysql.com/doc/refman/4.1/en/union.html

MySQL: Find "last modified" date from two tables

I have two MySQL tables: tech_requests and comments. I want to display each tech_request one time in a list ordered by the "last modified" date, whether that be the date of the tech_request creation or the latest comment tied to that tech_request. I was trying to use UNION but I got stuck. Any ideas would be much appreciated. Here are the tables:
CREATE TABLE `tech_requests` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`staff_member_id` int(3) NOT NULL,
`date_time` datetime NOT NULL,
`request` text NOT NULL,
`building_id` int(2) NOT NULL,
`technician_id` int(2) DEFAULT NULL,
`completed` tinyint(1) NOT NULL,
`subject` varchar(30) NOT NULL DEFAULT '',
`category_id` int(2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=203 DEFAULT CHARSET=utf8;
CREATE TABLE `comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tech_request_id` int(11) NOT NULL,
`technician_id` int(2) NOT NULL,
`date_time` datetime NOT NULL,
`comment` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=234 DEFAULT CHARSET=utf8;
Are you looking for something like this?
SELECT r.id, r.staff_member_id, ...,
GREATEST(r.date_time, COALESCE(c.date_time, 0)) last_modified
FROM tech_requests r LEFT JOIN
(
SELECT tech_request_id, MAX(date_time) date_time
FROM comments c
GROUP BY tech_request_id
) c
ON r.id = c.tech_request_id
ORDER BY last_modified
Here is SQLFiddle demo

How can I select distinct column based on max datetime (another column) also joining two tables in MySQL?

I've read many somewhat similar questions here and tried everything I can think of, without success. I think I've found the question based on a single table, or without the need for getting a distinct column, but not my situation exactly.
I want to get distinct ticker_symbol and corresponding ticker_name and latest ticker_quote based on these tables:
CREATE TABLE `tickers` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ticker_symbol` varchar(6) COLLATE utf8_unicode_ci NOT NULL,
`ticker_name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `ticker_quotes` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ticker_symbol` varchar(6) COLLATE utf8_unicode_ci NOT NULL,
`ticker_quote` float(8,2) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`updated_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=111 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
Try
SELECT q.ticker_symbol, t.ticker_name, q.ticker_quote
FROM (SELECT ticker_symbol, MAX(created_at) created_at
FROM ticker_quotes
GROUP BY ticker_symbol) m JOIN
ticker_quotes q ON m.ticker_symbol = q.ticker_symbol
AND m.created_at = q.created_at JOIN
tickers t ON q.ticker_symbol = t.ticker_symbol
SQLFiddle

Getting a duplicate key error in MYSQL. No duplicate found

I have a table. (Code taken from table generation code, I did not write this)
DROP TABLE IF EXISTS `CatalogueBasket`;
CREATE TABLE `CatalogueBasket` (
`ID` int(11) NOT NULL auto_increment,
`Shopper` char(35) NOT NULL default '',
`ItemLink` int(11) NOT NULL default '0',
`Quantity` int(11) NOT NULL default '0',
`Created` datetime NOT NULL default '0000-00-00 00:00:00',
`ExpectedDelivery1` datetime default NULL,
`ExpectedDelivery2` datetime default NULL,
`Comments` char(255) default NULL,
`Status` int(10) unsigned default NULL,
`QuantityShipped` int(10) unsigned default NULL,
`HarmonyNumber` int(10) unsigned default NULL,
`StartDate` datetime default NULL,
KEY `ID` (`ID`),
KEY `Shopper` (`Shopper`),
KEY `ItemLink` (`ItemLink`),
KEY `Quantity` (`Quantity`),
KEY `Created` (`Created`)
) TYPE=MyISAM;
When trying to insert a new Row at the end of this table I am getting the following message.
Duplicate entry '116604' for key 1
The insert statement is:
INSERT INTO CatalogueBasket (Shopper,ItemLink,Quantity,Created, Status, StartDate)
VALUES ('0.80916300 1338507348',58825,1,'2012-06-01 09:58:23', 0, '0-0-0')
I'm assuming it is talking about the ID column.
If I run the following query I get 116603 as the last key
SELECT * FROM `CatalogueBasket` order by ID desc limit 1
Any insight / help into this is appreciated.