Is cross-table indexing possible?

前端 未结 3 596
遇见更好的自我
遇见更好的自我 2020-12-14 02:10

Consider a structure where you have a many-to-one (or one-to-many) relationship with a condition (where, order by, etc.) on both tables. For example:

CREATE         


        
3条回答
  •  生来不讨喜
    2020-12-14 02:12

    As you know, SQLServer achieves this with indexed views:

    indexed views provide additional performance benefits that cannot be achieved using standard indexes. Indexed views can increase query performance in the following ways:

    Aggregations can be precomputed and stored in the index to minimize expensive computations during query execution.

    Tables can be prejoined and the resulting data set stored.

    Combinations of joins or aggregations can be stored.

    In SQLServer, to take advantage of this technique, you must query over the view and not over the tables. That means that you should know about the view and indexes.

    MySQL does not have indexed views, but you can simulate the behavior with table + triggers + indexes.

    Instead of creating a view, you must create an indexed table, a trigger to keep the data table up to date, and then you must query your new table instead of your normalized tables.

    You must evaluate if the overhead of write operations offsets the improvement in read operations.

    Edited:

    Note that it is not always necessary to create a new table. For example, in a 1:N relationship (master-detail) trigger, you can keep a copy of a field from the 'master' table into the 'detail' table. In your case:

    CREATE TABLE tableOne (
        id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
        tableTwoId INT UNSIGNED NOT NULL,
        objectId INT UNSIGNED NOT NULL,
        desnormalized_eventTime DATETIME NOT NULL,
        INDEX (objectID),
        FOREIGN KEY (tableTwoId) REFERENCES tableTwo (id)
    ) ENGINE=InnoDB;
    
    CREATE TRIGGER tableOne_desnormalized_eventTime
       BEFORE INSERT ON tableOne
    for each row
    begin
      DECLARE eventTime DATETIME;
      SET eventTime = 
          (select eventTime 
           from tableOne
           where tableOne.id = NEW.tableTwoId);
      NEW.desnormalized_eventTime = eventTime;
    end;
    

    Notice that this is a before insert trigger.

    Now, the query is rewritten as follows:

    select * from tableOne t1 
      inner join tableTwo t2 on t1.tableTwoId = t2.id
      where t1.objectId = '..'
      order by t1.desnormalized_eventTime;
    

    Disclaimer: not tested.

提交回复
热议问题