1

次のプリペアドステートメントを使用します。

    SELECT * 
    FROM 
        c_members,c_users,c_positions,c_done_meetings
    WHERE 
        c_positions.POS_ID=c_users.POS_ID 
        AND c_members.CLUB_ID = ? 
        AND USER_POINTS >= ?
        AND USER_POINTS <= ? 
        AND c_users.POS_ID LIKE ? 
        AND MEM_ACADEMY LIKE ? 
        AND MEM_SEX LIKE ? 
        AND MEM_GRADELVL LIKE ? 
        AND MEM_GPA >= ? 
        AND MEM_GPA <= ? 
        AND MEM_ARCHIVE = 0 
GROUP BY 
    c_members.MEM_ID, c_members.CLUB_ID 
HAVING 
    SUM(c_done_meetings.MEDONE_ATTEND = 'u') >= 1 
ORDER BY 
    USER_POINTS DESC

ただし、このクエリは111レコードをロードするのに21.971405982971秒かかります。「HavingSUM(...)」句を削除すると、パフォーマンスが100%向上します。それをより良く最適化する方法はありますか?

編集:(テーブル構造)

    CREATE TABLE IF NOT EXISTS `c_done_meetings` (
  `MEM_ID` int(11) NOT NULL,
  `CLUB_ID` int(11) NOT NULL,
  `MEETING_ID` int(11) NOT NULL,
  `MEDONE_ATTEND` varchar(1) NOT NULL COMMENT 'E=excused, U=unexcused, P=present',
  UNIQUE KEY `unique` (`MEM_ID`,`CLUB_ID`,`MEETING_ID`),
  KEY `MEETING_ID` (`MEETING_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    CREATE TABLE IF NOT EXISTS `c_members` (
  `MEM_ID` int(11) NOT NULL,
  `CLUB_ID` int(11) NOT NULL,
  `MEM_FIRST` varchar(50) NOT NULL,
  `MEM_MIDDLE` varchar(50) DEFAULT NULL,
  `MEM_LAST` varchar(50) NOT NULL,
  `MEM_SEX` tinyint(1) NOT NULL COMMENT '0-Male 1-Female',
  `MEM_EMAIL` varchar(100) DEFAULT NULL,
  `MEM_GRADELVL` int(11) NOT NULL,
  `MEM_ACADEMY` varchar(50) DEFAULT '',
  `MEM_GPA` double DEFAULT '0',
  `MEM_ADDRESS` varchar(500) DEFAULT NULL,
  `MEM_CITY` varchar(100) DEFAULT NULL,
  `MEM_STATE` varchar(100) DEFAULT NULL,
  `MEM_ZIP` int(11) DEFAULT NULL,
  `MEM_TELEPHONE` varchar(25) DEFAULT NULL,
  `MEM_AP` tinyint(1) NOT NULL,
  `MEM_HONORS` tinyint(1) NOT NULL,
  `MEM_ESOL` tinyint(1) NOT NULL,
  `MEM_HISP` tinyint(1) NOT NULL,
  `MEM_WHITE` tinyint(1) NOT NULL,
  `MEM_MULTI` tinyint(1) NOT NULL,
  `MEM_NATIVE` tinyint(1) NOT NULL,
  `MEM_BLACK` tinyint(1) NOT NULL,
  `MEM_ASIAN` tinyint(1) NOT NULL,
  `MEM_EXTRA` varchar(10000) DEFAULT NULL,
  `MEM_ARCHIVE` tinyint(1) NOT NULL DEFAULT '0',
  UNIQUE KEY `MEM_ID` (`MEM_ID`,`CLUB_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

    CREATE TABLE IF NOT EXISTS `c_positions` (
  `POS_ID` int(11) NOT NULL AUTO_INCREMENT,
  `CLUB_ID` int(11) NOT NULL,
  `POS_NAME` varchar(20) NOT NULL,
  `POS_DESC` varchar(500) NOT NULL,
  `POS_ADMIN` tinyint(1) NOT NULL,
  `POS_ATN_VIEW` tinyint(1) NOT NULL,
  `POS_ATN_CHKIN` tinyint(1) NOT NULL,
  `POS_ATN_FINALIZE` tinyint(1) NOT NULL,
  `POS_MEM_VIEW` tinyint(1) NOT NULL,
  `POS_MEM_ADD` tinyint(1) NOT NULL,
  `POS_MEM_EDIT` tinyint(1) NOT NULL,
  `POS_POS_VIEW` tinyint(1) NOT NULL,
  `POS_POS_ADD` tinyint(1) NOT NULL,
  `POS_POS_EDIT` tinyint(1) NOT NULL,
  `POS_MEET_VIEW` tinyint(1) NOT NULL,
  `POS_MEET_ADD` tinyint(1) NOT NULL,
  `POS_MEET_EDIT` tinyint(1) NOT NULL,
  `POS_EVENT_VIEW` tinyint(1) NOT NULL,
  `POS_EVENT_ADD` tinyint(1) NOT NULL,
  `POS_EVENT_EDIT` tinyint(1) NOT NULL,
  `POS_EVENT_UPDATE` tinyint(1) NOT NULL,
  `POS_REPORT_VIEW` tinyint(1) NOT NULL,
  `POS_ARCHIVE_VIEW` tinyint(1) NOT NULL,
  `POS_ANNOUNCEMENTS` tinyint(1) NOT NULL,
  `POS_WEB_CUSTOM` tinyint(1) NOT NULL,
  PRIMARY KEY (`POS_ID`),
  UNIQUE KEY `UNIQUE_NAME` (`CLUB_ID`,`POS_NAME`)
) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=14 ;

    CREATE TABLE IF NOT EXISTS `c_users` (
  `MEM_ID` int(11) NOT NULL,
  `CLUB_ID` int(11) NOT NULL,
  `USER_PIN` int(11) NOT NULL,
  `USER_POINTS` double NOT NULL,
  `POS_ID` int(11) NOT NULL,
  `USER_ARCHIVE` tinyint(1) NOT NULL DEFAULT '0',
  UNIQUE KEY `MEM_ID` (`MEM_ID`,`CLUB_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

編集2:はい、すべてのIDにインデックスが付けられ、SUM(...)> =#は欠席した会議の数を計算します。#はユーザーが設定するパラメーターです(テスト用に1をハードコーディングしました)

4

3 に答える 3

1

WHERE句で使用されるすべてのフィールド、テーブルが結合されるすべてのフィールド(現在、デカルト結合を取得しているので、結合条件を明示的に指定する必要があります)、グループ化に使用されるすべてのフィールドにインデックスを付ける必要があります。並べ替えに使用されるすべてのフィールド。

最後の問題はHAVINGそこにある節です。インデックスは計算値であるため、そのためにインデックスを使用することはできません。これがシステムで頻繁に使用されるクエリである場合(つまり、レポート用だけでなく)、このフィルタリングの目的でフラグとして使用できるフィールドを追加することを検討してください。クエリのいずれかを設定c_done_meetings.MEDONE_ATTEND = 'u'するときはいつでも、メンバーやユーザー、またはこれに関連付けられているものにこのフラグを設定して、WHERE句で簡単にフィルタリングできるフィールドを作成することもできます。

uそれ以外では、副選択でその値を持つユーザーまたはメンバーのリストを減らし、その副選択をテーブルとして使用して参加することで、実際にパフォーマンスが向上する可能性があります。

編集:

実際のテーブル構造を確認すると、インデックスを追加する必要がある場所がはっきりとわかります。また、なぜあなたがテーブルc_usersc_members持っていて、まったく同じ主キーを持っているのか疑問に思っています。なぜこれらは単一のテーブルではないのでしょうか?

于 2013-02-20T22:33:16.420 に答える
0

テーブルを非正規化し、SUM(c_done_meetings.MEDONE_ATTEND ='u')> = 1を表すc_membersにフィールドを追加できます。ただし、 c_done_meetingsを更新するときは、常にそのフィールドを更新する必要があります(トリガーで実行できます)

また、LIKE条件を回避するようにしてください。使用=インシード(少なくともSEXでは可能)

于 2013-02-20T22:36:47.810 に答える
0

私に飛び出すいくつかのこと:

あなたはかなりよく使うようです。これが必要ないように、phpコードで何かをしてみてください。たとえば、mem_sexには限られた数の選択肢があります。フロントエンドをラジオボタンまたはドロップダウンにして、likeの代わりに=を使用できる値を送信します。

2つ目は、select句にsum()を追加し、適切なgroup by句を追加すると、実行速度が向上するはずです。それは一撃の価値があります。

于 2013-02-20T22:32:16.307 に答える