2012-05-26 34 views
0

我有一個表(MySQL)有一個名爲binID的列。此列中的值可以在1到70之間。如何使用唯一的列值作爲輸入到另一個select語句

我想要做的是選擇此列的唯一值(應該是1到70之間的數字),然後使用每個值對它們進行迭代(讓我們稱它爲theBinID)作爲參數到另一個SELECT語句如:

SELECT * FROM MyTable WHERE binID = theBinID ORDER BY createdDate DESC LIMIT 10 

基本上,我期待得到每個binID最近的10行。

我不相信有一種方法有一個基本的SQL語句,要做到這一點,但我會愛是答案,所以我寫了創建的SELECT DISTINCT binIDs的遊標的存儲過程,然後遍歷它並填充臨時表。

我的問題是,這是爲了優化,如果我取100K行,我得到1.7秒的平均時間。執行我的存儲過程以獲得700行(10個記錄,70個分檔)需要1.4秒。我意識到0.3秒可以被認爲是相當大的改進,但我希望能夠獲得100K行這個亞秒。

有沒有更好的方法?

完整的存儲過程是這樣的:

BEGIN 
DECLARE done INT DEFAULT FALSE; 
DECLARE binID INT; 
DECLARE cur1 CURSOR FOR SELECT DISTINCT heatmapBinID from MEStressTest ORDER BY heatmapBinID ASC; 
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; 

DROP TEMPORARY TABLE IF EXISTS TempResults; 

CREATE TEMPORARY TABLE TempResults (
    `recordID` text NOT NULL, 
    `queryTerm` text NOT NULL, 
    `recordCreated` double(11,0) NOT NULL, 
    `recordByID` text NOT NULL, 
    `recordByName` text NOT NULL, 
    `recordText` text NOT NULL, 
    `recordSource` text NOT NULL, 
    `rerecordCount` int(11) NOT NULL DEFAULT '0', 
    `timecodeOffset` int(11) NOT NULL DEFAULT '-1', 
    `recordByImageURL` text NOT NULL, 
    `canDelete` int(11) NOT NULL DEFAULT '1', 
    `heatmapBinID` int(11) DEFAULT NULL, 
    `timelineBinID` int(11) DEFAULT NULL, 
    PRIMARY KEY (`recordID`(20)) 
); 

OPEN cur1; 

read_loop: LOOP 
    FETCH cur1 INTO binID; 

    IF done THEN 
     LEAVE read_loop; 
    END IF; 

    INSERT INTO TempResults (recordID, queryTerm, recordCreated, recordByID, recordByName, recordText, recordSource, rerecordCount, timecodeOffset, recordByImageURL, canDelete, heatmapBinID, timelineBinID) 
    SELECT * FROM MEStressTest WHERE heatmapBinID = binID ORDER BY recordCreated DESC LIMIT numRecordsPerBin; 
END LOOP; 

CLOSE cur1; 

SELECT * FROM TempResults ORDER BY heatmapBinID ASC, recordCreated DESC; 

END

回答

1

儘量模擬ROW_NUMBER在MySQL OVER PARTITION:http://www.sqlfiddle.com/#!2/fd8b5/4

鑑於這樣的數據:

create table sentai(
    band varchar(50), 
    member_name varchar(50), 
    member_year int not null 
); 

insert into sentai(band, member_name, member_year) values 
('BEATLES','JOHN',1960), 
('BEATLES','PAUL',1961), 
('BEATLES','GEORGE',1962), 
('BEATLES','RINGO',1963), 
('VOLTES V','STEVE',1970), 
('VOLTES V','MARK',1971), 
('VOLTES V','BIG BERT',1972), 
('VOLTES V','LITTLE JOHN',1973), 
('VOLTES V','JAMIE',1964), 
('ERASERHEADS','ELY',1990), 
('ERASERHEADS','RAYMUND',1991), 
('ERASERHEADS','BUDDY',1992), 
('ERASERHEADS','MARCUS',1993); 

對象,找到每個樂隊的所有三個最新成員。

首先,我們必須把基於2008年全年各部件上的ROW_NUMBER(通過降序)

select *, 

    @rn := @rn + 1 as rn 
from (sentai s, (select @rn := 0) as vars) 
order by s.band, s.member_year desc; 

輸出:

|  BAND | MEMBER_NAME | MEMBER_YEAR | @RN := 0 | RN | 
|-------------|-------------|-------------|----------|----| 
|  BEATLES |  RINGO |  1963 |  0 | 1 | 
|  BEATLES |  GEORGE |  1962 |  0 | 2 | 
|  BEATLES |  PAUL |  1961 |  0 | 3 | 
|  BEATLES |  JOHN |  1960 |  0 | 4 | 
| ERASERHEADS |  MARCUS |  1993 |  0 | 5 | 
| ERASERHEADS |  BUDDY |  1992 |  0 | 6 | 
| ERASERHEADS |  RAYMUND |  1991 |  0 | 7 | 
| ERASERHEADS |   ELY |  1990 |  0 | 8 | 
| VOLTES V | LITTLE JOHN |  1973 |  0 | 9 | 
| VOLTES V | BIG BERT |  1972 |  0 | 10 | 
| VOLTES V |  MARK |  1971 |  0 | 11 | 
| VOLTES V |  STEVE |  1970 |  0 | 12 | 
| VOLTES V |  JAMIE |  1964 |  0 | 13 | 

然後我們重置的行數時,成員是上不同的帶:

select *, 

    @rn := IF(@pg = s.band, @rn + 1, 1) as rn, 
    @pg := s.band 
from (sentai s, (select @pg := null, @rn := 0) as vars) 
order by s.band, s.member_year desc; 

輸出:

|  BAND | MEMBER_NAME | MEMBER_YEAR | @PG := NULL | @RN := 0 | RN | @PG := S.BAND | 
|-------------|-------------|-------------|-------------|----------|----|---------------| 
|  BEATLES |  RINGO |  1963 |  (null) |  0 | 1 |  BEATLES | 
|  BEATLES |  GEORGE |  1962 |  (null) |  0 | 2 |  BEATLES | 
|  BEATLES |  PAUL |  1961 |  (null) |  0 | 3 |  BEATLES | 
|  BEATLES |  JOHN |  1960 |  (null) |  0 | 4 |  BEATLES | 
| ERASERHEADS |  MARCUS |  1993 |  (null) |  0 | 1 | ERASERHEADS | 
| ERASERHEADS |  BUDDY |  1992 |  (null) |  0 | 2 | ERASERHEADS | 
| ERASERHEADS |  RAYMUND |  1991 |  (null) |  0 | 3 | ERASERHEADS | 
| ERASERHEADS |   ELY |  1990 |  (null) |  0 | 4 | ERASERHEADS | 
| VOLTES V | LITTLE JOHN |  1973 |  (null) |  0 | 1 |  VOLTES V | 
| VOLTES V | BIG BERT |  1972 |  (null) |  0 | 2 |  VOLTES V | 
| VOLTES V |  MARK |  1971 |  (null) |  0 | 3 |  VOLTES V | 
| VOLTES V |  STEVE |  1970 |  (null) |  0 | 4 |  VOLTES V | 
| VOLTES V |  JAMIE |  1964 |  (null) |  0 | 5 |  VOLTES V | 

然後我們每個波段只選擇最近的三個成員:

select x.band, x.member_name, x.member_year 
from 
(
    select *, 
    @rn := IF(@pg = s.band, @rn + 1, 1) as rn, 
    @pg := s.band 
    from (sentai s, (select @pg := null, @rn := 0) as vars) 
    order by s.band, s.member_year desc 
) as x 
where x.rn <= 3 
order by x.band, x.member_year desc; 

輸出:

|  BAND | MEMBER_NAME | MEMBER_YEAR | 
|-------------|-------------|-------------| 
|  BEATLES |  RINGO |  1963 | 
|  BEATLES |  GEORGE |  1962 | 
|  BEATLES |  PAUL |  1961 | 
| ERASERHEADS |  MARCUS |  1993 | 
| ERASERHEADS |  BUDDY |  1992 | 
| ERASERHEADS |  RAYMUND |  1991 | 
| VOLTES V | LITTLE JOHN |  1973 | 
| VOLTES V | BIG BERT |  1972 | 
| VOLTES V |  MARK |  1971 | 

雖然窗函數(例如。 ROW_NUMBER OVER PARTITION)在MySQL上尚未提供,只需使用變量進行模擬即可。請讓我們知道這是不是光標方法快


怎麼看起來像窗口功能的RDBMS:http://www.sqlfiddle.com/#!1/fd8b5/6

with member_recentness as 
(
    select row_number() over each_band as recent, * 
    from sentai 
    window each_band as (partition by band order by member_year desc) 
) 
select * 
from member_recentness 
where recent <= 3; 

輸出:

| RECENT |  BAND | MEMBER_NAME | MEMBER_YEAR | 
|--------|-------------|-------------|-------------| 
|  1 |  BEATLES |  RINGO |  1963 | 
|  2 |  BEATLES |  GEORGE |  1962 | 
|  3 |  BEATLES |  PAUL |  1961 | 
|  1 | ERASERHEADS |  MARCUS |  1993 | 
|  2 | ERASERHEADS |  BUDDY |  1992 | 
|  3 | ERASERHEADS |  RAYMUND |  1991 | 
|  1 | VOLTES V | LITTLE JOHN |  1973 | 
|  2 | VOLTES V | BIG BERT |  1972 | 
|  3 | VOLTES V |  MARK |  1971 | 
0
SELECT * FROM MyTable WHERE binID IN (SELECT DISTINCT(bin_id) FROM mysql_table) ORDER BY createdDate DESC LIMIT 10; 

這不是測試,請不要介意語法。

添加索引以提高性能。

+0

感謝您的答覆,但這與SELECT * FROM MyTable ORDER BY createdDate DESC LIMIT 10相同,它只給出表格中的前10行,而不是每個bin中的前10行。 – Raconteur

0

如果試圖內加入2個表沒有任何加盟的關鍵,這將是兩個表的笛卡爾積,即:

SELECT * 
FROM MyTable t 
    INNER JOIN (SELECT DISTINCT binId FROM MyTable) AS u 
WHERE 
    t.binID = theBinID 
ORDER BY t.createdDate DESC LIMIT 10 

你可以參考this

+0

乾杯,Raymomd。不知道我明白這一點(BID從哪裏來),但它似乎產生表格的前10行而不是每個bin,很像下面的答案。 – Raconteur

相關問題