0

binIDという列を持つテーブル(MySQL)があります。この列の値の範囲は1〜70です。

私がやりたいのは、この列の一意の値(1から70までの数値である必要があります)を選択し、それぞれをパラメーターとして使用して、次のような別のSELECTステートメントにそれらを繰り返し処理することです。

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

基本的に、binIDごとに最新の10行を取得しようとしています。

基本的なSQLステートメントでこれを行う方法はないと思いますが、それが答えになることを望んでいるので、binIDのSELECT DISTINCTにカーソルを作成し、それを繰り返すストアドプロシージャを作成しました。一時テーブルにデータを入力します。

私の問題は、これは最適化のためであり、100K行をフェッチすると、平均時間は1.7秒になります。700行(70ビンに対して10レコード)を取得するためにストアドプロシージャを実行すると、1.4秒かかります。0.3秒はかなりの改善と見なされる可能性があることを認識していますが、10万行でこの1秒未満になることを望んでいます。

もっと良い方法はありますか?

完全なストアドプロシージャは次のとおりです。

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;

終わり

4

3 に答える 3

1

MySQLでROW_NUMBEROVERPARTITIONをシミュレートしてみてください: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);

オブジェクト、各バンドの最新の3人のメンバーすべてを見つけます。

まず、ほとんどの年に基づいて(降順で)各メンバーに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 |

次に、各バンドの最新の3人のメンバーのみを選択します。

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 |
于 2012-05-26T02:51:06.840 に答える
0
SELECT * FROM MyTable WHERE binID IN (SELECT DISTINCT(bin_id) FROM mysql_table) ORDER BY createdDate DESC LIMIT 10;

これはテストされていません。構文を気にしないでください。

インデックスを追加してパフォーマンスを向上させます。

于 2012-05-26T01:22:47.097 に答える
0

結合キーなしで2つのテーブルを内部結合しようとすると、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

あなたはこれを参照することができます

于 2012-05-26T02:02:43.560 に答える