waanders
waanders

Reputation: 9083

Optimization of a MySQL view

I want to join two MySQL tables and store it as a view, so I can address this view in a application in stead of querying two tables. But this view occurs to be extremely slow.

This are my tables:

CREATE TABLE spectrumsets (
    setid INT(11) NOT NULL,
    timestampdt INT(11) NULL DEFAULT NULL,
    timestampd INT(10) UNSIGNED NOT NULL,
    timestampt INT(10) UNSIGNED NOT NULL,
    device INT(11) NOT NULL,
    methodname VARCHAR(50) NOT NULL,
    PRIMARY KEY (setid),
    UNIQUE INDEX setid_idx (setid),
    UNIQUE INDEX timestamp_device_idx (timestampd, timestampt, device),
    INDEX device_fk (device),
    INDEX timestampd_idx (timestampd),
    CONSTRAINT device_fk FOREIGN KEY (device)
        REFERENCES spectrumdevices (deviceid)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB

CREATE TABLE spectrumdata (
    valueid INT(11) NOT NULL AUTO_INCREMENT,
    spectrumset INT(11) NOT NULL,
    wavelength DOUBLE NULL DEFAULT NULL,
    intensity DOUBLE NULL DEFAULT NULL,
    PRIMARY KEY (valueid),
    INDEX spectrumset_idx (spectrumset),
    CONSTRAINT spectrumset_fk FOREIGN KEY (spectrumset)
        REFERENCES spectrumsets (setid)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB

And this is my view:

SELECT spectrumsets.timestampd,spectrumsets.timestampt,spectrumsets.device,
    spectrumdata.wavelength,spectrumdata.intensity
FROM spectrumdata INNER JOIN spectrumsets ON spectrumdata.spectrumset=
    spectrumsets.setid
WHERE spectrumdata.wavelength>0 
ORDER BY spectrumsets.timestampd,spectrumsets.timestampt,spectrumsets.device,
    spectrumdata.wavelength

A select count(*) on my machine takes 385.516 seconds and results into 82923705 records, so a rather large dataset

I already found this link but still don't fully understand what's wrong.

UPDATE:

EXPLAIN gives this results:

"id","select_type","table","type","possible_keys","key","key_len","ref","rows","Extra"
"1","SIMPLE","spectrumsets","index","PRIMARY,setid_idx","timestamp_device_idx","12",NULL,"327177","Using index; Using temporary; Using filesort"
"1","SIMPLE","spectrumdata","ref","spectrumset_idx","spectrumset_idx","4","primprod.spectrumsets.setid","130","Using where"

Upvotes: 1

Views: 136

Answers (1)

Neville Kuyt
Neville Kuyt

Reputation: 29629

Explain suggests that the query is hitting the indices for the join (which is good), but then using a temporary table and file sort for the rest of the query.

This is for two reasons:

  • the where clause isn't hitting the index
  • the order by clause isn't hitting the index

In a comment, you say that removing the where clause has lead to a big improvement; that suggests you need the compound index on spectrumset, wavelength, assuming wavelength has a decent number of possible values (if it's just 10 values, an index may not do anything).

If you leave the "order by" clause out of your view, it should go a lot faster - and there's a good case for letting sort order be determined by the query extracting data, not the view. I'm guessing most queries will be very selective about the data - limiting to a few timestamps; by embedding the order by in the view, you pay the price for sorting every time.

If you really must have the "order by" in the view, create an index that includes all fields in the order of the "order by", with the join at the front. For instance:

UNIQUE INDEX timestamp_device_idx (set_id, timestampd, timestampt, device),

Upvotes: 2

Related Questions