3
\$\begingroup\$

I have a table vanrust_corev2.tblPlayerLog that has approx 6.7k records, I also have a table in a different database vanrust_forum.tblPlayerAvatars which has approx 6.7k records.

The purpose of this script is to pull the SteamID of players who don't have an avatar stored for them yet. However the issue here is, the execution time of this script is often 29-31 seconds which seemed a little strange to me as I'm sure there are much more sophisticated and larger databases that would not have this issue.

SELECT
*
FROM
vanrust_corev2.tblPlayerLog log
WHERE
not exists(
SELECT 
a.SteamID
FROM vanrust_forum.tblPlayerAvatars a
WHERE a.Steamid = log.SteamID)

This is for the same user, just to a different database.

This script works perfectly the only issue here is execution time so I'm hoping for some pointers on where I could be going wrong.

Here is the execution plan:

exec-plan

\$\endgroup\$
  • \$\begingroup\$ Please update your title to reflect what your code does. \$\endgroup\$ – Nic Hartley Jun 16 '15 at 5:14
  • \$\begingroup\$ I think the fact you are querying across two different servers has something to do with it. Hard to say without seeing the execution plan, though. \$\endgroup\$ – Phrancis Jun 16 '15 at 5:15
  • \$\begingroup\$ Hey, it's the same user/server, just a different database - does this make a difference ? \$\endgroup\$ – zanderwar Jun 16 '15 at 5:22
  • \$\begingroup\$ Maybe, maybe not. Your query looks fine, it's probably something else. Can you post the execution plan with it? Just take a screenshot of it and attach it as a picture. \$\endgroup\$ – Phrancis Jun 16 '15 at 5:31
6
\$\begingroup\$

I normally wouldn't recommend this, but...

According to your query execution plan, it is doing 22719171 table scans in order to fetch the next row. What I think the problem stems from is querying across databases, which may have to open a connection for each Handler_read_rnd_next, then close the connection each time. One way or the other, if your columns are properly indexed, something like this shouldn't take near that long. I think something about the setup is causing the optimizer to go into a loop across two databases, and SQL is not good at looping. To make this more set-based, I'd suggest pulling your data sets into one of the two databases with a construct like a temp table:

START TRANSACTION;
  DROP TEMPORARY TABLE IF EXISTS vanrust_corev2.users_with_avatars;
  CREATE TEMPORARY TABLE vanrust_corev2.users_with_avatars (SteamID INT NOT NULL);
  INSERT INTO vanrust_corev2.users_with_avatars (SteamId) VALUES
    SELECT 
      a.SteamID
    FROM vanrust_forum.tblPlayerAvatars a
COMMIT;

Then, you could simply join the record sets within the vanrust_corev2 database. This would increase I/O for a bit, but likely remove the need to connect between 2 databases millions of times while it does table scans:

SELECT
*
FROM
vanrust_corev2.tblPlayerLog log
WHERE
NOT EXISTS (
  SELECT 
  a.SteamID
  FROM vanrust_corev2.users_with_avatars a
  WHERE a.Steamid = log.SteamID
);

And of course it's a good idea to DROP TEMPORARY TABLE vanrust_corev2.users_with_avatars; when you are done, although it will otherwise automatically drop when the session is ended with the database.


On another note, I strongly recommend you start naming aliases in a way that describes what they represent. log is OK, but a doesn't seem to mean anything.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.