1

円グラフでレポートとして使用されるレコードセットを作成する次のクエリがあります。

特に頻繁に実行されることはありませんが、実行されると数秒かかります。より効率的にする方法はないかと思います。

SELECT
  CASE
    WHEN (lastStatus IS NULL)     THEN 'Unused'
    WHEN (attempts > 3 AND callbackAfter IS NULL)   THEN 'Max Attempts Reached'
    WHEN (callbackAfter IS NOT NULL AND callbackAfter >  DATE_ADD(NOW(), INTERVAL 7 DAY)) THEN 'Call Back After 7 Days'
    WHEN (callbackAfter IS NOT NULL AND callbackAfter <= DATE_ADD(NOW(), INTERVAL 7 DAY)) THEN 'Call Back Within 7 Days'
    WHEN (archived = 0)     THEN 'Call Back Within 7 Days'
    ELSE 'Spoke To'
  END AS statusSummary,
  COUNT(leadId) AS total
FROM
  CO_Lead
WHERE
  groupId = 123
  AND
  deleted = 0
GROUP BY
  statusSummary
ORDER BY
  total DESC;

groupId, deleted)のインデックスがありますが、他のフィールドをインデックスに追加するのに役立つかどうかはわかりません(追加する場合は、どちらを最初に使用するかをどのように決定しますかcallbackAfter?最も使用されているためですか?)

テーブルには約500,000行があります(ただし、これから1年で10倍になります)。

私が考えることができた他の唯一のことは、それを6つのクエリに分割することでした(WHEN句をWHEREに移動しました)が、それは3倍の時間がかかります。

編集:

これがテーブルの定義です

CREATE TABLE CO_Lead (
  objectId                             int UNSIGNED       NOT NULL AUTO_INCREMENT,
  groupId                              int UNSIGNED       NOT NULL,
  numberToCall                         varchar(20)        NOT NULL,
  firstName                            varchar(100)       NOT NULL,
  lastName                             varchar(100)       NOT NULL,
  attempts                             tinyint            NOT NULL default 0,
  callbackAfter                        datetime           NULL,
  lastStatus                           varchar(30)        NULL,
  createdDate                          datetime           NOT NULL,
  archived                             bool               NOT NULL default 0,
  deleted                              bool               NOT NULL default 0,
  PRIMARY KEY (
    objectId
  )
) ENGINE = InnoDB;
ALTER TABLE CO_Lead ADD CONSTRAINT UQIX_CO_Lead UNIQUE INDEX (
  objectId
);
ALTER TABLE CO_Lead ADD INDEX (
  groupId,
  archived,
  deleted,
  callbackAfter,
  attempts
);
ALTER TABLE CO_Lead ADD INDEX (
  groupId,
  deleted,
  createdDate,
  lastStatus
);
ALTER TABLE CO_Lead ADD INDEX (
  firstName
);
ALTER TABLE CO_Lead ADD INDEX (
  lastName
);
ALTER TABLE CO_Lead ADD INDEX (
  lastStatus
);
ALTER TABLE CO_Lead ADD INDEX (
  createdDate
);
4

2 に答える 2

1

インデックスを削除して、パフォーマンスが向上するかどうかを確認してください。

一部のデータベースでは、インデックスは必ずしもパフォーマンスを向上させるとは限りません。インデックスがある場合、MySQLは常にそれを使用します。この場合、それはインデックスを読み取ることを意味し、次に各ページからデータを読み取る必要があります。ページの読み取りは、シーケンシャルではなくランダムです。このランダムな読み取りは、とにかくすべてのページを読み取らなければならないクエリで、パフォーマンスを低下させる可能性があります。

于 2012-11-29T22:10:31.527 に答える
1

ノート:

  1. leadIdできない場合はNULL、をに変更COUNT(leadId)COUNT(*)ます。それらは論理的に同等ですが、MySQLオプティマイザのほとんどのバージョンはそれを識別するのにそれほど賢くありません。
  2. 2つの冗長なcallbackAfter IS NOT NULL条件を削除します。2番目の部分を満たす場合callbackAfter、とにかくnullにすることはできません。
  3. クエリを6つの部分に分割し、それぞれに適切なインデックスを追加することでメリットが得られますが、の条件CASEが重複しているかどうかによっては、間違った結果または正しい結果が得られる場合があります。

可能な書き換え(異なる形式に注意し、これが同じ結果を返すかどうかを確認してください、そうでない場合があります!)

SELECT
    cnt1 AS "Unused"
  , cnt2 AS "Max Attempts Reached"
  , cnt3 AS "Call Back After 7 Days"
  , cnt4 AS "Call Back Within 7 Days"
  , cnt5 AS "Call Back Within 7 Days"
  , cnt6 - (cnt1+cnt2+cnt3+cnt4+cnt5) AS "Spoke To"
FROM
  ( SELECT
      ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
          AND lastStatus IS NULL
      ) AS cnt1
    , ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
          AND attempts > 3 AND callbackAfter IS NULL
      ) AS cnt2
    , ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
          AND callbackAfter >  DATE_ADD(NOW(), INTERVAL 7 DAY)
      ) AS cnt3
    , ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
          AND callbackAfter <= DATE_ADD(NOW(), INTERVAL 7 DAY)
      ) AS cnt4
    , ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
          AND archived = 0
      ) AS cnt5
    , ( SELECT COUNT(*)  FROM CO_Lead
        WHERE groupId = 123 AND deleted = 0
      ) AS cnt6
  ) AS tmp ;

正しい結果が返される場合は、各サブクエリに使用されるインデックスを追加できます。

サブクエリ1の場合: (groupId, deleted, lastStatus)

サブクエリ2、3、4の場合: (groupId, deleted, callbackAfter, attempts)

サブクエリ5の場合: (groupId, deleted, archived)


別のアプローチは、あなたが持っているクエリを保持し(上記の注1と2のみを念頭に置いて)、幅広いカバーインデックスを追加することです。

 (groupId, deleted, lastStatus, callbackAfter, attempts, archived)
于 2012-11-30T02:30:50.047 に答える