Speeding up multi-table joins with MySQL - mysql

I have 3 tables in which I'm trying to preform joins on, and inserting the resulting data into another table. The query is taking anywhere between 15-30 mins depending on the dataset. The tables I'm selecting from and joining on are at least 25k records each but will quickly grow to be 500k+.
I tried adding indexes on the fields but still isn't helping that much. Are there any other things I can try or are joins on this scale just going to take this long?
Here is the query I'm trying to perform:
INSERT INTO audience.topitem
(runs_id, total_training_count, item, standard_index_value, significance, seed_count, nonseed_count, prod, model_type, level_1, level_2, level_3, level_4, level_5)
SELECT 5, seed_count + nonseed_count AS total_training_count,
ii.item, standard_index_value, NULL, seed_count, nonseed_count,
standard_index_value * seed_count AS prod, 'site', topic_L1, topic_L2, topic_L3, topic_L4, topic_L5
FROM audience.item_indexes ii
LEFT JOIN audience.usercounts uc ON ii.item = uc.item AND ii.runs_id = uc.runs_id
LEFT JOIN categorization.categorization at on ii.item = at.url
WHERE ii.runs_id = 5
Table: audience.item_indexes
CREATE TABLE `item_indexes` (
`item` varchar(1024) DEFAULT NULL,
`standard_index_value` float DEFAULT NULL,
`runs_id` int(11) DEFAULT NULL,
`model_type` enum('site','term','combo') DEFAULT NULL,
KEY `item_idx` (`item`(333))
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Table: audience.usercounts
CREATE TABLE `usercounts` (
`item` varchar(1024) DEFAULT NULL,
`seed_count` int(11) DEFAULT NULL,
`nonseed_count` int(11) DEFAULT NULL,
`significance` float(19,6) DEFAULT NULL,
`runs_id` int(11) DEFAULT NULL,
`model_type` enum('site','term','combo') DEFAULT NULL,
KEY `item_idx` (`item`(333))
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
Table: audience.topitem
CREATE TABLE `topitem` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`total_training_count` int(11) DEFAULT NULL,
`item` varchar(1024) DEFAULT NULL,
`standard_index_value` float(19,6) DEFAULT NULL,
`significance` float(19,6) DEFAULT NULL,
`seed_count` int(11) DEFAULT NULL,
`nonseed_count` int(11) DEFAULT NULL,
`prod` float(19,6) DEFAULT NULL,
`cat_type` varchar(32) DEFAULT NULL,
`cat_level` int(11) DEFAULT NULL,
`conf` decimal(19,9) DEFAULT NULL,
`level_1` varchar(64) DEFAULT NULL,
`level_2` varchar(64) DEFAULT NULL,
`level_3` varchar(64) DEFAULT NULL,
`level_4` varchar(64) DEFAULT NULL,
`level_5` varchar(64) DEFAULT NULL,
`runs_id` int(11) DEFAULT NULL,
`model_type` enum('site','term','combo') DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=825 DEFAULT CHARSET=utf8;
Table: categorization.categorization
CREATE TABLE `AT_categorization` (
`url` varchar(760) NOT NULL ,
`language` varchar(10) DEFAULT NULL,
`category` text,
`entity` text,
`source` varchar(255) DEFAULT NULL,
`topic_L1` varchar(45) NOT NULL DEFAULT '',
`topic_L2` varchar(45) NOT NULL DEFAULT '',
`topic_L3` varchar(45) NOT NULL DEFAULT '',
`topic_L4` varchar(45) NOT NULL DEFAULT '',
`topic_L5` varchar(45) NOT NULL DEFAULT '',
`last_refreshed` datetime DEFAULT NULL,
PRIMARY KEY (`url`,`topic_L1`,`topic_L2`,`topic_L3`,`topic_L4`,`topic_L5`),
UNIQUE KEY `inx_url` (`url`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

If you add the following indexes, your query will run faster:
CREATE INDEX runs_idx ON audience.item_indexes (runs_id);
ALTER TABLE audience.usercounts
DROP INDEX item_idx,
ADD INDEX item_idx (runs_id, item(333));
Also, item_indexes is utf8, but AT_categorization is latin1, which keeps any indexes from being used. To address this issue, change AT_categorization to utf8:
ALTER TABLE AT_categorization CHARSET=utf8;
Lastly, for the AT_categorization table, the two indexes
PRIMARY KEY (`url`,`topic_L1`,`topic_L2`,`topic_L3`,`topic_L4`,`topic_L5`),
UNIQUE KEY `inx_url` (`url`)
are redundant. So you could DROP these, and simply have the url field be the primary key:
ALTER TABLE AT_categorization
DROP PRIMARY KEY,
DROP KEY `inx_url`,
ADD PRIMARY KEY (url);

Related

Cant create a relation in mysql - Error creating foreign key on id_produk (check data types)

here is my table :
CREATE TABLE `pesanan` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`ref_number` varchar(50) NOT NULL DEFAULT '',
`id_produk` int(11) NOT NULL,
`id_user` int(11) NOT NULL,
`qty` int(11) NOT NULL,
`total` varchar(50) NOT NULL DEFAULT '',
`tanggal` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=latin1;
i want to create a relation of id_produk to table produk.id and id_user to user.id, here is the other table :
CREATE TABLE `produk` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`id_kategori` int(11) NOT NULL,
`status` varchar(10) NOT NULL DEFAULT '',
`slug` varchar(100) NOT NULL DEFAULT '',
`judul` varchar(100) NOT NULL DEFAULT '',
`harga` varchar(10) DEFAULT '',
`target` int(11) DEFAULT NULL,
`desc` text,
`cover` varchar(100) DEFAULT NULL,
`tanggal` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=29 DEFAULT CHARSET=latin1;
and user table
CREATE TABLE `user` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`suspended` int(11) DEFAULT NULL,
`level` varchar(11) DEFAULT NULL,
`nama` varchar(100) DEFAULT NULL,
`email` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`alamat` text,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=latin1;
when i try to relation it , it give me this error :
Error creating foreign key on id_produk (check data types)
The columns should have the exact same data type in both tables. In your case in the "produk" and "user" tables they are unsigned, which means they go from 0 to 4294967295 but in the "pesanan" table they are signed which means they go from -2147483648 to 2147483647. See more here.
If the server allowed you to create such foreign keys, it would possibly create situations where, for example, a user is added with and ID of 2147483648 that cannot ever be referenced in the "pesanan" table.
You should change the "id_produk" and "id_user" columns in the "pesanan" table to be unsigned.

mysql join query is slow compared with mssql

I have the following simple join query
SELECT
count(*)
FROM
DBx.caseview p2015
INNER JOIN DBy.caseview p2014 ON p2015.casenumber=p2014.casenumber;
For some reason it just leaves MySQL hanging there for a lot of time until I get tired and cancel it. On the contrary, if run exactly the same code on MSSQL with the same data set the query takes a few seconds at most.
Is there a parameter that needs to be changed on MySQL to speed up this type of queries?
Here's my table in MySQL
CREATE TABLE `caseview` (
`ID` bigint(20) NOT NULL AUTO_INCREMENT,
`CASEID` varchar(18) DEFAULT NULL,
`CASENUMBER` int(10) DEFAULT NULL,
`ACCOUNTID` varchar(18) DEFAULT NULL,
`ACCOUNT` varchar(256) DEFAULT NULL,
`ASSETID` varchar(18) DEFAULT NULL,
`SAPPRODUCTGROUP` varchar(10) DEFAULT NULL,
`PRODUCT` varchar(128) DEFAULT NULL,
`FAMILY` varchar(128) DEFAULT NULL,
`CONTACTID` varchar(18) DEFAULT NULL,
`OWNERID` varchar(18) DEFAULT NULL,
`TYPE` varchar(128) DEFAULT NULL,
`PRIORITY` varchar(24) DEFAULT NULL,
`ORIGIN` varchar(24) DEFAULT NULL,
`SUBJECT` varchar(256) DEFAULT NULL,
`STATUS` varchar(24) DEFAULT NULL,
`LASTACTIVITY` varchar(1024) DEFAULT NULL,
`INITALDESCRIPTION` varchar(1024) DEFAULT NULL,
`CLOSEDDATE` datetime DEFAULT NULL,
`CREATEDDATE` datetime DEFAULT NULL,
`LASTMODIFIEDDATE` datetime DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `ID_UNIQUE` (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=122393 DEFAULT CHARSET=utf8;
There's two tables with exactly the same configuration as above, just different data
DBx.caseview p2015 has 197647 rows
DBy.caseview p2014 has 122392 rows
Create an Index for CASENUMBER field.
ALTER TABLE `caseview` ADD INDEX ( `CASENUMBER` ) ;
Give it a few seconds to create the index and run the query again.

How to add foreign key in table using existing column, without losing data?

I have a table in which I need to add foreign key on an existing column. Following is create table:
CREATE TABLE `itemtx` (
`itemTxid` int(11) NOT NULL AUTO_INCREMENT,
`itemcode` varchar(1) NOT NULL,
`weight` decimal(7,3) DEFAULT NULL,
`txtype` varchar(10) DEFAULT 'Pickup',
`tripstopid` int(11) NOT NULL,
`barcode` varchar(25) DEFAULT NULL,
`bagcount` int(11) DEFAULT '1',
PRIMARY KEY (`itemTxid`)
) ENGINE=InnoDB AUTO_INCREMENT=33524 DEFAULT CHARSET=latin1
I need to add foreign key on tripstopid column. I cannot drop or empty table as it contains data. Following is the referenced table:
CREATE TABLE `tripstop` (
`tripstopid` int(11) NOT NULL AUTO_INCREMENT,
`tripid` int(11) DEFAULT NULL,
`locationName` varchar(100) DEFAULT NULL,
`userName` varchar(100) DEFAULT NULL,
`locationid` int(11) DEFAULT NULL,
`datetime` varchar(20) DEFAULT NULL,
`createts` varchar(20) DEFAULT NULL,
`latitude` double DEFAULT NULL,
`longitude` double DEFAULT NULL,
`userid` int(11) DEFAULT NULL,
`tid` int(11) DEFAULT NULL,
PRIMARY KEY (`tripstopid`)
) ENGINE=InnoDB AUTO_INCREMENT=4691 DEFAULT CHARSET=latin1
How can I do this without losing my data?
You can achieve this by following:
ALTER TABLE itemtx
ADD FOREIGN KEY (tripstopid) REFERENCES tripstop(tripstopid);
Verified by creating tables, inserting data in them and then updating table for foreign key, previously entered data is not lost.

Hibernate - How to map two tables on two columns?

I have two tables:
CREATE TABLE `framework_files` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fileName` varchar(777) DEFAULT NULL,
`fileSize` float DEFAULT NULL,
`filePath` varchar(777) DEFAULT NULL,
`fileUrl` varchar(777) DEFAULT NULL,
`linkedObjectID` int(11) DEFAULT NULL,
`linkedObjectName` varchar(250) DEFAULT NULL,
`active` int(11) DEFAULT '0',
`uploadDate` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`uploadersIP` varchar(77) DEFAULT NULL,
`uploadersIPXFORWARDEDFOR` varchar(77) DEFAULT NULL,
`userName` varchar(777) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `q_idx` (`linkedObjectID`,`linkedObjectName`)
) ENGINE=InnoDB AUTO_INCREMENT=110 DEFAULT CHARSET=utf8;
And second table
CREATE TABLE `publicSitePortfolioWorks` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`mainName` varchar(100) DEFAULT NULL,
`tableName` varchar(250) DEFAULT 'publicSitePortfolioWorks',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
I need to map publicSitePortfolioWorks to framework_files on framework_files.linkedObjectID=publicSitePortfolioWorks.id and framework_files.linkedObjectName=publicSitePortfolioWork.tableName .
I.e. publicSitePortfolioWorks have many objects of framework_files. All child objects must be in Set, like
private Set<FrameworkFiles> fileTEST = new HashSet<>(0);
How to map this Set in hbm.xml file? At this moment no foreign key between these two tables.

Perf of select mysql query is really bad

I'm not sure why this query is taking 4 minutes to complete:
SELECT
su.sid,u.uid,u.display_name,u.locale
FROM user u
LEFT JOIN subscription_user su ON su.uid = u.uid
ORDER BY u.display_name DESC
LIMIT 0,25;
Well, I know it's due to the order, remove it and it's very fast. If I change to using INNER JOIN instead it's fast but the issue is not all users may be in the subscription_user table.
CREATE TABLE `user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`password` varchar(100) DEFAULT NULL,
`user_type` varchar(10) NOT NULL DEFAULT 'user',
`display_name` varchar(50) NOT NULL,
`email` varchar(100) NOT NULL,
`locale` varchar(8) DEFAULT 'en',
`last_login` datetime DEFAULT NULL,
`auth_type` varchar(10) DEFAULT NULL,
`auth_data` varchar(500) DEFAULT NULL,
`inactive` tinyint(4) NOT NULL DEFAULT '0',
`receive_email` tinyint(4) NOT NULL DEFAULT '1',
`stateid` int(10) DEFAULT NULL,
`owner_group_id` int(11) DEFAULT NULL,
`signature` varchar(500) DEFAULT NULL,
`raw_signature` varchar(500) DEFAULT NULL,
`round_robin` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`uid`),
UNIQUE KEY `email` (`email`),
KEY `stateid` (`stateid`) USING BTREE,
KEY `user_type` (`user_type`) USING BTREE,
KEY `name` (`display_name`)
) ENGINE=InnoDB AUTO_INCREMENT=28343 DEFAULT CHARSET=latin1;
CREATE TABLE `subscription_user` (
`sid` varchar(50) NOT NULL,
`uid` int(11) NOT NULL,
`deleted` tinyint(4) NOT NULL DEFAULT '0',
`forum_user` varchar(50) NOT NULL,
PRIMARY KEY (`sid`,`uid`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
When you have an SQL query, the index can only really help you if the first column in the index is part of the query.
Your query joins su.uid = u.uid and the optimizer will not be able to use that to reference the first column in the subscription primary key index.
You should either reverse the order of the columns in the primary key, or alternatively, you should add a foreign key index, or an independent index on the uid