Scott weist auf einen wichtigen Punkt bezüglich der aufeinanderfolgenden Markttage hin. Ich empfehle, dies mit einer Verbindungstabelle wie der folgenden zu behandeln:
CREATE TABLE `market_days` (
`market_day` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`date` DATE NOT NULL DEFAULT '0000-00-00',
PRIMARY KEY USING BTREE (`market_day`),
UNIQUE KEY USING BTREE (`date`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0
;
Je mehr Markttage vergehen, desto INSERT
neu date
Werte in der Tabelle. market_day
wird entsprechend erhöht.
Beim Einfügen prices
Daten, suchen Sie die LAST_INSERT_ID()
oder den entsprechenden Wert für einen bestimmten date
für vergangene Werte.
Was die prices
Tabelle selbst, können Sie Ablagemöglichkeiten schaffen, SELECT
y INSERT
viel effizienter mit einem nützlichen PRIMARY KEY
und keine AUTO_INCREMENT
Spalte. In dem unten stehenden Schema ist Ihre PRIMARY KEY
enthält an sich nützliche Informationen und ist nicht nur eine Konvention zur Kennzeichnung eindeutiger Zeilen. Verwendung von MEDIUMINT
(3 Bytes) anstelle von INT
(4 Byte) spart ein zusätzliches Byte pro Zeile und, was noch wichtiger ist, 2 Byte pro Zeile in der PRIMARY KEY
- und bietet dennoch über 16 Millionen mögliche Daten und Tickersymbole (jeweils).
CREATE TABLE `prices` (
`market_day` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0',
`ticker_id` MEDIUMINT(8) UNSIGNED NOT NULL DEFAULT '0',
`price` decimal (7,2) NOT NULL DEFAULT '00000.00',
PRIMARY KEY USING BTREE (`market_day`,`ticker_id`),
KEY `ticker_id` USING BTREE (`ticker_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1
;
In diesem Schema ist jede Zeile eindeutig für jedes Paar von market_day
y ticker_id
. Hier ticker_id
entspricht einer Liste von Tickersymbolen in einer tickers
Tabelle mit einem ähnlichen Schema wie die market_days
Tisch:
CREATE TABLE `tickers` (
`ticker_id` MEDIUMINT(8) UNSIGNED NOT NULL AUTO_INCREMENT,
`ticker_symbol` VARCHAR(5),
`company_name` VARCHAR(50),
/* etc */
PRIMARY KEY USING BTREE (`ticker_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=0
;
Das Ergebnis ist eine ähnliche Abfrage wie bei anderen Vorschlägen, jedoch mit zwei wichtigen Unterschieden: 1) Es gibt keine funktionale Transformation der Datumsspalte, was die Fähigkeit von MySQL zerstört, Schlüssel in der Verknüpfung zu benutzen; in der folgenden Anfrage benutzt MySQL einen Teil der PRIMARY KEY
zum Beitritt am market_day
. 2) MySQL kann nur einen Schlüssel pro JOIN
o WHERE
Klausel. In dieser Anfrage verwendet MySQL die volle Breite der PRIMARY KEY
( market_day
y ticker_id
), während in der vorherigen Abfrage nur einer verwendet werden konnte (MySQL wählt normalerweise den selektiveren der beiden aus).
SELECT
`market_days`.`date`,
`tickers`.`ticker_symbol`,
`yesterday`.`price` AS `close_yesterday`,
`today`.`price` AS `close_today`,
(`today`.`price` - `yesterday`.`price`) / (`yesterday`.`price`) AS `pct_change`
FROM
`prices` AS `today`
LEFT JOIN
`prices` AS `yesterday`
ON /* uses PRIMARY KEY */
`yesterday`.`market_day` = `today`.`market_day` - 1 /* this will join NULL for `today`.`market_day` = 0 */
AND
`yesterday`.`ticker_id` = `today`.`ticker_id`
INNER JOIN
`market_days` /* uses first 3 bytes of PRIMARY KEY */
ON
`market_days`.`market_day` = `today`.`market_day`
INNER JOIN
`tickers` /* uses KEY (`ticker_id`) */
ON
`tickers`.`ticker_id` = `today`.`ticker_id`
WHERE
`today`.`price` > 0
AND
`yesterday`.`price` > 0
;
Ein weiterer Punkt ist die Notwendigkeit, sich auch gegen tickers
y market_days
zur Anzeige der aktuellen ticker_symbol
y date
aber diese Operationen sind sehr schnell, da sie Schlüssel verwenden.