4

テーブル

各行は、特定の日付の特定の時間に放送されたビデオを表しています。1日あたり約1600本のビデオがあります。

CREATE TABLE `air_video` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `date` DATE NOT NULL,
    `time` TIME NOT NULL,
    `duration` TIME NOT NULL,
    `asset_id` INT(10) UNSIGNED NOT NULL,
    `name` VARCHAR(100) NOT NULL,
    `status` VARCHAR(100) NULL DEFAULT NULL,
    `updated` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    UNIQUE INDEX `date_2` (`date`, `time`),
    INDEX `date` (`date`),
    INDEX `status` (`status`),
    INDEX `asset_id` (`asset_id`)
)
ENGINE=InnoDB

タスク

2つの条件があります。

  1. 各動画は1日24回以下で表示する必要があります。
  2. 各動画は72時間以内にローテーションする必要があります。

ローテーションとは、最初からビデオが最後に放送されたときまでの期間を意味します。

したがって、ユーザーが指定した日付範囲を指定して、これらの条件に違反するすべてのビデオを選択する必要があります。

結果は、日ごとおよびasset_id(ビデオID)ごとにグループ化する必要があります。例えば:

      date      asset_id          name           dailyCount      rotationSpan
   2012-04-27      123      whatever_the_name         35              76
   2012-04-27      134      whatever_the_name2        39              20
   2012-04-28      125      whatever_the_name3        26              43

クエリ

今までに私はこのクエリを書きました:

SELECT
    t1.date, t1.asset_id, t1.name,
    (SELECT 
        COUNT(t3.asset_id) 
        FROM air_video AS t3 
        WHERE t2.asset_id = t3.asset_id AND t3.date = t1.date
    ) AS 'dailyCount',
    MIN(CONCAT(t2.date, ' ', t2.time)) AS 'firstAir',
    MAX(CONCAT(t2.date, ' ', t2.time)) AS 'lastAir',
    ROUND(TIMESTAMPDIFF(
        MINUTE,
        MIN(CONCAT(t2.date, ' ', t2.time)),
        MAX(CONCAT(t2.date, ' ', t2.time)) 
    ) / 60) as 'rotationSpan'
FROM
    air_video AS t1
INNER JOIN
    air_video AS t2 ON
        t1.asset_id = t2.asset_id 
WHERE
    t1.status NOT IN ('bumpers', 'clock', 'weather')
    AND t1.date BETWEEN '2012-04-01' AND '2012-04-30'
GROUP BY
    t1.asset_id, t1.date
HAVING
    `rotationSpan` > 72
    OR `dailyCount` > 24
ORDER BY
    `date` ASC,
    `rotationSpan` DESC,
    `dailyCount` DESC    

問題

  1. ユーザーが指定した日の範囲が大きいほど、クエリの完了にかかる時間が長くなります(1か月の範囲の場合は約9秒かかります)
  2. lastAirタイムスタンプは、特定の日付にビデオが放映された最新の時刻ではなく、完全に放映された最新の時刻です。
4

1 に答える 1

3

クエリを高速化する必要がある場合は、3行目のselect subクエリを削除する必要があります。それでもそのカウントを保持するには、最初に使用した正確なパラメータを使用してfrom句で再度内部結合できます。これはそれがどのように見えるべきかです:

SELECT
    t1.date, t1.asset_id, t1.name,
    COUNT(t3.asset_id) AS 'dailyCount',
    MIN(CONCAT(t2.date, ' ', t2.time)) AS 'firstAir',
    MAX(CONCAT(t2.date, ' ', t2.time)) AS 'lastAir',
    ROUND(TIMESTAMPDIFF(
        MINUTE,
        MIN(CONCAT(t2.date, ' ', t2.time)),
        MAX(CONCAT(t2.date, ' ', t2.time)) 
    ) / 60) as 'rotationSpan'
FROM
    air_video AS t1
INNER JOIN
    air_video AS t2 ON
        (t1.asset_id = t2.asset_id)
INNER JOIN
    air_video AS t3 
        ON (t2.asset_id = t3.asset_id AND t3.date = t1.date)
WHERE
    t1.status NOT IN ('bumpers', 'clock', 'weather')
    AND t1.date BETWEEN '2012-04-01' AND '2012-04-30'
GROUP BY
    t1.asset_id, t1.date
HAVING
    `rotationSpan` > 72
    OR `dailyCount` > 24
ORDER BY
    `date` ASC,
    `rotationSpan` DESC,
    `dailyCount` DESC

t2は日付に拘束されないため、日付範囲ではなく、明らかにテーブル全体を見ていることになります。

編集: 日付のバインドが多いため、クエリの実行が遅すぎます。その後、別のアプローチを取りました。私は3つのビューを作成しました(ビューなしで通常のクエリに組み合わせることができますが、最終結果のクエリの方が好きです)

--T1--

CREATE VIEW t1 AS select date,asset_id,name from air_video where (status not in ('bumpers','clock','weather')) group by asset_id,date order by date;

--T2--

CREATE VIEW t2 AS select t1.date,t1.asset_id,t1.name,min(concat(t2.date,' ',t2.time)) AS 'firstAir',max(concat(t2.date,' ',t2.time)) AS 'lastAir',round((timestampdiff(MINUTE,min(concat(t2.date,' ',t2.time)),max(concat(t2.date,' ',t2.time))) / 60),0) AS 'rotationSpan' from (t1 join air_video t2 on((t1.asset_id = t2.asset_id))) group by t1.asset_id,t1.date;

--T3--

CREATE VIEW t3 AS select t2.date,t2.asset_id,t2.name,count(t3.asset_id) AS 'dailyCount',t2.firstAir,t2.lastAir,t2.rotationSpan AS rotationSpan from (t2 join air_video t3 on(((t2.asset_id = t3.asset_id) and (t3.date = t2.date)))) group by t2.asset_id,t2.date;

そこから、次のクエリを実行できます。

SELECT
    date,
    asset_id, 
    name,
    dailyCount,
    firstAir,
    lastAir,
    rotationSpan
FROM
    t3
WHERE
    date BETWEEN '2012-04-01' AND '2012-04-30'
    AND (
        rotationSpan > 72
        OR 
        dailyCount > 24
    )
ORDER BY
    date ASC,
    rotationSpan DESC,
    dailyCount DESC
于 2012-05-17T10:36:57.630 に答える