使用多個不等式索引 GROUP BY Select
我有兩個需要幫助的相關問題:
問題 #1:如何索引表以優化“分組依據”SELECT
我有一個包含以下 Create 語句的股票價格資訊表:
CREATE TABLE `price_daily` ( `Symbol` varchar(20) NOT NULL, `Date` date NOT NULL, `Price` float DEFAULT NULL, `MarketCap` double DEFAULT NULL, `PriceToEarnings` double DEFAULT NULL, `PriceToSales` double DEFAULT NULL, PRIMARY KEY (`Symbol`,`Date`), KEY `Date_MCap` (`Date`,`MarketCap`,`PriceToSales`,`Symbol`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
這張表相當寬泛;它跨越大約 1 億行。因此,不精確的 SELECT 查詢可能需要很長時間才能解決,我想避免這種情況。
我希望能夠在數據庫中搜尋指定日期範圍內屬於所選 PriceToSales 和/或 PriceToEarnings 範圍內的股票。下面的查詢是我將執行的典型查詢:
SELECT Symbol, Date, MarketCap, Price FROM price_daily WHERE Date BETWEEN '2002-07-31'AND '2017-07-31' AND MarketCap >= 1000 AND PriceToSales BETWEEN 2 AND 5 GROUP BY Symbol ;
我使用 GROUP BY 是因為我只需要查看每個符號的一個結果。問題是,當我在末尾添加“GROUP BY”子句時,查詢的完成時間突然比沒有該子句時要長很多倍。我究竟做錯了什麼?我認為這與我的索引有關,但我還沒有 100% 弄清楚在索引中對列進行排序的“規則”。(一些非特定的細節:如果沒有 GROUP BY,查詢的完成時間大約為 0.5 秒,但獲取時間超過 200 秒,因為可能有數百萬個結果要顯示。)
編輯 20 年 4 月 28 日下午 3 點:我在多個位置被告知,上述 GROUP BY 查詢的語法不好,因為 Date、MarketCap 和 Price 列沒有聚合。這大概是一個需要解決的微不足道的問題;現在,我將問題 #1 單獨放在第二個問題上。
問題 #2:從 GROUPed 查詢中選擇最小值
與上述相關的問題:假設,我不想讓上面的“GROUP BY Symbol”子句選擇它想要的任何日期,而是要保證我的查詢將始終為每個符號按時間順序選擇最早的日期。我該怎麼做?我假設正確的查詢看起來像這樣:
SELECT Symbol, MIN(Date) FROM price_daily WHERE Date BETWEEN '2002-07-31'AND '2017-07-31' AND MarketCap >= 1000 AND PriceToSales BETWEEN 2 AND 5 GROUP BY Symbol ;
…但是,由於上述 GROUP BY 的問題,我目前無法對此進行測試。
對這些問題中的一個或兩個提供的任何幫助將不勝感激。如果您需要我提供更多資訊,我將在明天早上回到辦公室時編輯這篇文章。
**編輯 20 年 4 月 28 日下午 3:30:**問題 #2 下給出的查詢的解釋如下:
+------+-------------+-------------+-------+--------------------+-----------+---------+------+----------+-----------------------------------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +------+-------------+-------------+-------+--------------------+-----------+---------+------+----------+-----------------------------------------------------------+ | 1 | SIMPLE | price-daily | range | PRIMARY, date_mcap | date_mcap | 21 | NULL | 50622081 | Using where; using index; using temporary; using filesort | +------+-------------+-------------+-------+--------------------+-----------+---------+------+----------+-----------------------------------------------------------+ 1 row in set (0.00 sec)
查詢花費了331.1 秒來解決,生成了 2735 行。表格摘錄:
Symbol Date ------ ---------- A 2003-12-19 AABA 2007-07-26 AACC 2005-10-03 AAN 2010-02-11 AAOI 2017-03-07 AAON 2013-10-01 AAPL 2004-10-05 AAT 2012-07-27 ... ...
似乎有很多符合條件的行,數據庫伺服器需要對它們進行排序以進行分組。如果您的數據不適合記憶體,它甚至可能需要在磁碟上創建一個臨時表。記憶體中臨時表的大小受 max_heap_table_size 和 tmp_table_size 變數的限制,但更重要的是 - MEMORY 表使用固定長度的行儲存格式。VARCHAR 等可變長度類型使用固定長度儲存。這意味著每個 varchar(20) 值將消耗 20 字節的 RAM。為日期添加 3 個字節,為雙精度添加 4 個字節,您的行大小將為 31 個字節。如果 1 億行中有 5% 符合條件,那麼您需要 150 MB 臨時表來對數據進行分組。您可以從增加最大臨時表大小開始並檢查它是否有幫助。
但您也可以嘗試使用另一種方法:
SELECT Symbol ,(SELECT Date FROM price_daily WHERE Symbol = s.Symbol AND Date BETWEEN '2002-07-31'AND '2017-07-31' AND MarketCap >= 1000 AND PriceToSales BETWEEN 2 AND 5 ORDER BY Date LIMIT 1) AS min_date FROM symbols AS s;
我假設您有一個包含符號列表的表(符號數據類型應該相同)。