简体   繁体   中英

How to make my SELECT query more efficient?

I'm a beginner in SQL and I have some troubles with this request, which just can't be executed because it's too inefficient. Here it is, it just loads for hours (!)

SELECT my_db_client_total.email as EMAIL_TOTAL, 
    my_db_client_total.name, my_db_client_total.country 
    FROM my_db_client_total, my_db_client_pro
      WHERE (my_db_client_total.email<>'' ) 
    AND (my_db_client_total.country = '120') 
    AND (my_db_client_total.email IN (SELECT my_db_client_pro.email 
    FROM my_db_client_pro));

My tables are organised in this way :

Table 1 :        Table 2 :
   email         email
   name          name
   country       country

The purpose of the request it to test my database, and to process a further request where I want to select email , name and country from Table 1 where table1.email is not in table2 .

Sorry for my bad English, and for my level, as I said earlier, I'm a beginner and self-taught.

If anyone can help me or at least enlighten me, I'll be so thankful for your time.

EDIT: I didn't precisely know but I'm working with a table where there is 20 000+ rows.

Your question states you are using MySQL, so this will give you an inner (record must exist in both tables) join.

SELECT my_db_client_total.email as EMAIL_TOTAL, my_db_client_total.name, my_db_client_total.country 
FROM my_db_client_total inner join my_db_client_pro on my_db_client_pro.email = my_db_client_total.email
WHERE (my_db_client_total.email<>'' ) AND (my_db_client_total.country = '120');

To select a row that does not exist in the other table do this:

SELECT my_db_client_total.email as EMAIL_TOTAL, my_db_client_total.name, my_db_client_total.country 
FROM my_db_client_total LEFT OUTER JOIN my_db_client_pro on my_db_client_pro.email = my_db_client_total.email
WHERE (my_db_client_total.email<>'' ) AND (my_db_client_total.country = '120') AND my_db_client_pro.email IS NULL;

This is your query (fixed up a bit with table aliases):

SELECT ct.email as EMAIL_TOTAL, ct.name, ct.country
FROM my_db_client_total ct 
WHERE (ct.email <> '' ) AND
      (ct.country = 120) AND 
      (ct.email IN (SELECT my_db_client_pro.email FROM my_db_client_pro));

(I am assuming that 120 is really an integer.)

In older versions of MySQL, exists is more efficient than in , so rewrite the query as:

SELECT ct.email as EMAIL_TOTAL, ct.name, ct.country
FROM my_db_client_total ct 
WHERE (ct.email <> '' ) AND
      (ct.country = 120) AND 
      EXISTS (SELECT 1 FROM my_db_client_pro cp WHERE cp.email = ct.email);

Next, consider indexes. For this query, good indexes are:

create index idx_my_db_client_total_2 on my_db_client_total(country, email, name);

create index idx_my_db_client_pro_email on my_db_client_pro(email);
SELECT my_db_client_total.email as EMAIL_TOTAL, 
  my_db_client_total.name, my_db_client_total.country 
FROM 
  my_db_client_total, 
WHERE (my_db_client_total.email <> '') 
AND (my_db_client_total.country = '120') 
AND (my_db_client_total.email not IN (SELECT my_db_client_pro.email
  FROM my_db_client_pro));

Basically get all the data from table and on where condition getting the email address not in table 2

You should be using a Join .

Check them out here: https://technet.microsoft.com/en-us/library/ms191472(v=sql.105).aspx

Example code:

SELECT my_db_client_total.email as EMAIL_TOTAL, my_db_client_total.name, my_db_client_total.country
FROM my_db_client_total AS ct
    CROSS JOIN my_db_client_pro AS cp
    ON ct.CLIENT_ID = cp.CLIENT_ID

If you join the 2 tables, why don't you use the right side table in your query instead of making a subquery on it?

Try this (only the join) :

SELECT my_db_client_total.email as EMAIL_TOTAL, my_db_client_total.name, my_db_client_total.country 
  FROM my_db_client_total, my_db_client_pro
 WHERE my_db_client_total.email <> ''
   AND my_db_client_total.country = '120'
   AND my_db_client_total.email = my_db_client_pro.email;

or this (only the subquery) :

SELECT my_db_client_total.email as EMAIL_TOTAL, my_db_client_total.name, my_db_client_total.country 
  FROM my_db_client_total
 WHERE my_db_client_total.email <> ''
   AND my_db_client_total.country = '120' 
   AND my_db_client_total.email IN (SELECT my_db_client_pro.email FROM my_db_client_pro);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM