Reputation: 174
I have a big problem, I'm not very good with SQL... I have a database in mysql and when I do this query I have a response time around the 0.2s, so when i call it for a list of users (in a servlet) the response time goes around lots of seconds..
SELECT visible,nlikes,nomecognome,profile_img,users_face.id
FROM users_face
LEFT OUTER JOIN `likes_face`
on (users_face.fb_id = likes_face.fb_id)
WHERE users_face.fb_id =? and users_face.token_valid=1
ORDER BY date DESC limit 1
Is there any way to optimize this code or any good resource to study the optimization of queries?
ArrayList<SocialMan> mans = new ArrayList<>();
PreparedStatement ps;
int nlikes, userid;
String nomeCogn, prof;
boolean visible;
FacebookClient facebookClient = new DefaultFacebookClient(token, Version.VERSION_2_6);
com.restfb.Connection<User> myFriends;
myFriends = facebookClient.fetchConnection("me/friends",User.class, Parameter.with("limit", 999));
for (User u : myFriends.getData()) {
nlikes = -1;
userid = -1;
nomeCogn = "ERROR";
prof = "ERROR";
visible = false;
try {
ps = con.prepareStatement("SELECT visible,nlikes,nomecognome,profile_img,users_face.id FROM users_face LEFT OUTER JOIN `likes_face` on (users_face.fb_id = likes_face.fb_id) WHERE users_face.fb_id =? and users_face.token_valid=1 ORDER BY date DESC limit 1");
ps.setString(1, "" + u.getId());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
nlikes = rs.getInt("nlikes");
userid = rs.getInt("id");
nomeCogn = rs.getString("nomecognome");
prof = rs.getString("profile_img");
visible = rs.getBoolean("visible");
}
} catch (SQLException ex) {
Logger.getLogger(FaceLikes.class.getName()).log(Level.SEVERE, null, ex);
}
// System.out.println("NOMECOGNOME: "+nomeCogn);
if (userid != -1 && visible) {
mans.add(new SocialMan(nomeCogn, userid, prof, nlikes));
}
}
nlikes = -1;
userid = -1;
nomeCogn = "ERROR";
prof = "ERROR";
CREATE TABLE IF NOT EXISTS `users_face` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fb_id` varchar(45) NOT NULL,
`fb_token` varchar(300) NOT NULL,
`nomecognome` varchar(100) NOT NULL,
`data_iscrizione` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
`profile_img` varchar(255) NOT NULL,
`visible` int(11) NOT NULL DEFAULT '1',
`TOKEN` varchar(255) NOT NULL,
`locale` varchar(255) NOT NULL,
`token_valid` tinyint(1) NOT NULL,
PRIMARY KEY (`id`,`fb_id`),
UNIQUE KEY `fb_id` (`fb_id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=173 ;
CREATE TABLE IF NOT EXISTS `likes_face` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`nlikes` int(11) NOT NULL,
`fb_id` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1182636 ;
Upvotes: 3
Views: 1109
Reputation: 142298
("Read this entire answer before starting to take action.")
This does not make sense:
PRIMARY KEY (`id`,`fb_id`),
UNIQUE KEY `fb_id` (`fb_id`),
UNIQUE KEY `id` (`id`)
Tentatively, change to
PRIMARY KEY(fb_id),
INDEX(id)
on the assumption that you usually look up the record by fb_id.
If you say "list of users". Do you mean that WHERE fb_id IN ( ... )
? Probably not since you have LIMIT 1
. Or do you mean that you call that SELECT
repeatedly?
Gag! likes_face
has an id that you are not using, plus fb_id
that you are using but is not indexed. Use the same id for both tables: either get rid of AUTO_INCREMENT
and change code logic for likes_face
, or get rid of id
and make fb_id
the PK for both tables.
Are these tables 1:1?
Something is wrong. Why does likes_face have
AUTO_INCREMENT=1182636, while there seem to be only 173 users? If the tables are 1:1, are you using
REPLACE`? You will run out of ids!
Restarting...
If the tables are 1:1:
id
on both tables and have PRIMARY KEY(fb_id)
on both tables,CHARACTER SET ascii
if Facebook limits ids to ascii,If likes_face
is a count of likes for each day:
id
on both tables,CHARACTER SET ascii
if Facebook limits ids to ascii,likes_face
PRIMARY KEY(fb_id, date)
.If the tables are 1:many in some other way, I can't make sense of the schema.
Upvotes: 3
Reputation: 139
You can use EXPLAIN of statement of MYSQL. Optimizing Queries with EXPLAIN
Someone suggested of creating indexes. Creating index is good option but avoid indexes if that column going to be modified frequently.
Upvotes: 0
Reputation: 562320
This is all I can come up with:
ALTER TABLE users_face ADD INDEX (fb_id, token_valid);
ALTER TABLE likes_face ADD INDEX (fb_id, nlikes, date);
You can't optimize the sorting, because the date
column is in your non-primary table.
If you want to optimize further, the next thing to do is to move the nlikes
and date
columns into the users_face table, then make the index on that table over the following columns in this order: (fb_id, token_valid, date, nlikes)
.
Then you can skip the join in your query, and the sort order will be the order of the index, so that will be optimized.
After that (or maybe before denormalizing), you should think about caching the data.
Upvotes: 2