Which update is faster using join or sequential?

2019-04-02 22:49发布

问题:

This question is in sequence of my previous Question required update same table on deletion a row.

I could write two solutions using Stored Procedure instead of trigger or nested-query .

Both use a helper function my_signal(msg).

A Stored Procedure to delete employee from Employee Table.

  • Fist Solution: use UPDATE rows in table, without join operation:
CREATE PROCEDURE delete_employee(IN dssn varchar(64))
BEGIN
    DECLARE empDesignation varchar(128);
    DECLARE empSsn         varchar(64);
    DECLARE empMssn        varchar(64);
     SELECT SSN, designation, MSSN  INTO empSsn, empDesignation, empMssn 
     FROM Employee 
     WHERE SSN = dssn;

   IF (empSsn IS NOT NULL) THEN
    CASE       
           WHEN empDesignation = 'OWNER' THEN 
               CALL my_signal('Error: OWNER can not deleted!');

           WHEN empDesignation = 'WORKER' THEN 
            DELETE FROM Employee WHERE SSN = empSsn;               

           WHEN empDesignation = 'BOSS' THEN 
               BEGIN 
                   UPDATE Employee
                   SET MSSN = empMssn
                   WHERE MSSN = empSsn;

                DELETE FROM Employee WHERE SSN = empSsn;                   

               END;
    END CASE;
   ELSE 
               CALL my_signal('Error: Not a valid row!');
   END IF;
END//  
  • Second solution: as I was suggested in my previous question using INNER JOIN
CREATE PROCEDURE delete_employee(IN dssn varchar(64))
BEGIN
    DECLARE empDesignation varchar(128);
    DECLARE empSsn         varchar(64);
    DECLARE empMssn        varchar(64);
      SELECT SSN, designation, MSSN  INTO empSsn, empDesignation, empMssn 
      FROM Employee 
      WHERE SSN = dssn;

   IF (empSsn IS NOT NULL) THEN
       IF (empDesignation = 'OWNER') THEN 
        CALL my_signal('Error: OWNER can not deleted!');
       END IF;

       UPDATE `Employee` A INNER JOIN `Employee` B ON A.SSN= B.MSSN
       SET B.MSSN = A.MSSN WHERE A.SSN = empSsn;

       DELETE FROM `Employee` WHERE SSN = empSsn;
   ELSE 
       CALL my_signal('Error: Not a valid row!');
   END IF;    
END//

I read here that using join is efficient for Efficient SELECT. But my problem includes only one table and I feel my solution(first) is much efficient than second because join will consume memory comparatively.

Please suggest me which is better and efficient, if Employee table is sufficiently large. Which is better for me? Reason

EDIT: I checked for small table consist of 7 rows only, and both solution take same time.

mysql> CALL delete_employee(4);
Query OK, 1 row affected (0.09 sec)

I know SQL function behaves non-deterministically because table heuristics. Which choice is better? Either if you have some idea How query can be further optimised.

回答1:

After a while of thinking I am almost sure it doesn't make a difference, first solution may be even slightly slower, but in a not measurable dimension.

First intention would be, that the first solution is faster because you first fetch data by id and update only if nessesary.

But MySQL internally does nothing else in the UPDATE .. JOIN statement, just internally and as a result of this probably more efficiently as well.

Your first solution doesn't catch a default case - what happens if I neither get WORKER or BOSS?

Also your execution time (0.09s) is extremely high, which can't be explained with what I know about your database so far.

Did you set any index?

EDIT:

After looking at the table structure you've posted here I have some improvement offers for the structure itself.

1. Use type int when you are storing integer values. The database can handle integer way more efficient

2. Why generate SSN by yourself? Using auto_increment on the PRIMARY KEY is much simpler to handle and saves you a lot of work when you add new employees

ALTER TABLE `Employee`
    CHANGE `SSN` `SSN` int(11) NOT NULL AUTO_INCREMENT ,
    CHANGE `MSSN` `MSSN` int(11) DEFAULT NULL,
    ADD KEY `KEY_Employee_MSSN` ( `MSSN` );

3. Do you use the name for lookups? If so, it needs to be unique as well

ALTER TABLE `Employee`
    ADD UNIQUE KEY `UNI_KEY_Employee` ( `name` );

4. Do you have a fixed range of designations? enum forces the input to be one of the defined values

ALTER TABLE `Employee`
    CHANGE `designation` `designation` ENUM( 'BOSS', 'WORKER' ) NOT NULL DEFAULT 'WORKER',
    ADD KEY `KEY_Employee_designation` ( `designation` );

Final structure

mysql> EXPLAIN `Employee`;

+-------------+-----------------------+------+-----+---------+----------------+
| Field       | Type                  | Null | Key | Default | Extra          |
+-------------+-----------------------+------+-----+---------+----------------+
| SSN         | int(11)               | NO   | PRI | NULL    | auto_increment |
| name        | varchar(64)           | YES  | UNI | NULL    |                |
| designation | enum('BOSS','WORKER') | NO   | MUL | WORKER  |                |
| MSSN        | int(11)               | YES  | MUL | NULL    |                |
+-------------+-----------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)