Home  >  Q&A  >  body text

Why does this query update fail to execute successfully?

<p>I have 2 tables, customers (3000 rows) and phone_call_log (350,000 rows). </p> <p>I need to implement the time of the last call to each customer using call logs (faster for frontend search). </p> <p>The index is as follows:</p> <ul> <li>start_time (timestamp)</li> <li>call(bigint(32) unsigned)</li> <li>Caller(bigint(32) unsigned)</li> <li>Phone number (bigint(32) unsigned)</li> <li>last_call(timestamp)</li> </ul> <p>When running this query, for the caller/callee columns, the completion time is less than 2 seconds without the OR statement, but with the OR statement, it will not complete (in testing, I did not let it run for more than 30 minutes ). </p> <pre class="brush:sql;toolbar:false;">UPDATE customers SET customers.last_call = ( SELECT max(phone_call_log.start_time) FROM phone_call_log WHERE phone_call_log.callee = customers.phonenumber OR phone_call_log.caller = customers.phonenumber ) WHERE customers.phonenumber IS NOT NULL AND length(customers.phonenumber) > 6 AND customers.phonenumber > 1000000; </pre></p>
P粉885562567P粉885562567413 days ago508

reply all(2)I'll reply

  • P粉009186469

    P粉0091864692023-09-04 14:58:45

    fastest

    When a call comes in, change the data flow to update customers.last_call.

    Update connection

    UPDATECompared with JOIN, IN (SELECT ...) works better.

    or

    OR will reduce performance. The query will most likely scan the entire phone_call_log for each customer.

    One workaround is to do two UPDATE, and use the appropriate index:

    UPDATE 
        SET customers.last_call = GREATEST( customers.last_call,
                     ( select max(phone_call_log.start_time)
                          FROM  phone_call_log
                         WHERE  phone_call_log.callee = customers.phonenumber 
                     )
        WHERE ...
    UPDATE 
        SET customers.last_call = GREATEST( customers.last_call,
                     ( ... caller ... )
                     )
        WHERE ...

    This requires creating the following index on phone_call_log:

    INDEX(callee, start_time)
        INDEX(caller, start_time)

    AndDelete the current single column index caller and callee.

    type of data

    For phone numbers, using BIGINT may be wrong, especially considering LENGTH(customers.phonenumber) > 6.

    Actually, all of this boils down to a simple test:

    where customers.phonenumber is not null
      AND LENGTH(customers.phonenumber) > 6
      AND customers.phonenumber > 1000000;

    Every > check checks NOT NULL; only one of them is used, depending on the data type, and indexed.

    (Please provide SHOW CREATE TABLE; 'English' is not accurate enough.)

    reply
    0
  • P粉354602955

    P粉3546029552023-09-04 10:38:38

    Queries using OR cannot effectively use the index. I suggest you try the following:

    UPDATE customers
    SET last_call = GREATEST(
        (SELECT MAX(start_time) FROM phone_call_log WHERE callee = customers.phonenumber),
        (SELECT MAX(start_time) FROM phone_call_log WHERE caller = customers.phonenumber)
    )

    Please note that GREATEST has issues handling NULL values.

    reply
    0
  • Cancelreply