斯科特提出了一個有關連續市場日的重要觀點。我建議用連接器表像處理這個:
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
;
隨着越來越多的市場天期限到期,只是在INSERT
表新date
值。 market_day
將相應增加。
當插入prices
數據時,查找LAST_INSERT_ID()
或對於過去值的給定date
的對應值。
對於prices
表本身,可以使存儲,SELECT
和INSERT
操作更加高效與實用PRIMARY KEY
並沒有AUTO_INCREMENT
列。在下面的模式中,您的PRIMARY KEY
包含內在有用的信息,而不僅僅是識別唯一行的慣例。使用MEDIUMINT
(3字節)而不是INT
(4字節)可以節省每行額外的一個字節,更重要的是在PRIMARY KEY
中每行節省2個字節 - 同時仍然提供超過1600萬個可能的日期和標記符號(每個)。
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
;
在這種模式中的每個行是在每個對market_day
和ticker_id
唯一的。這裏ticker_id
對應於股票代碼清單在tickers
表類似的模式應用到market_days
表:
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
;
這就產生了一個類似的查詢人提出,但有兩個重要的區別:1)有沒有職能轉變在日期列上,這破壞了MySQL在連接上使用密鑰的能力;在下面的查詢中,MySQL將使用部分PRIMARY KEY
加入market_day
。 2)MySQL每JOIN
或WHERE
子句只能使用一個密鑰。在這個查詢中,MySQL將使用PRIMARY KEY
(market_day
和ticker_id
)的全部寬度,而在之前的查詢中它只能使用一個(MySQL通常會選擇更多的選擇)。
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
;
更細的點是需要以顯示實際ticker_symbol
和date
,但這些操作都非常快,因爲它們使用的鍵也加入反對tickers
和market_days
。
@Scott:感謝您的評論。我可以將時間戳更改爲日期以使事情更輕鬆,而不必處理範圍。 – 2009-08-09 05:50:57
@Knix日期功能相當乾淨,不知道它有多昂貴,但肯定是你的電話。週末和假日市場關閉仍然存在問題。 previousClose列消除了自我加入,封閉市場日的混亂,以犧牲複製數據爲代價,並且在插入今日收盤時不得不知道prev close。 – Scott 2009-08-09 06:15:32
謝謝...我會接受你的建議! – 2009-08-09 06:43:52