2013-02-20 2 views
1

я использую следующий подготовленное заявление:MySQL Query Optimization (займет слишком много времени)

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 

Однако этот запрос занимает 21.971405982971 секунд, чтобы загрузить 111 записей. Когда я удаляю предложение «С SUM (...)», производительность на 100% лучше. Есть ли способ улучшить его лучше?

Edit: (Таблица структуры)

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; 

Edit 2: Да все идентификаторы индексируются, то SUM (...)> = # вычисляет количество пропущенных встреч. # Является параметром, устанавливаемый пользователем (я просто жестко закодирован 1 для тестирования)

+0

Как выглядят структуры таблицы? Вы используете индексы? – Mike

+4

Вы сделали EXPLAIN в запросе? –

+0

должен быть проиндексирован: c_positions.POS_ID, c_members.CLUB_ID, USER_POINTS, c_users.POS_ID, MEM_ACADEMY ... – 2013-02-20 22:26:53

ответ

0

Нужно иметь индексы для всех полей, используемых в предложении WHERE, во всех полях, в которых эти таблицы объединены (вам нужно явно указать условия соединения, как сейчас, вы получаете декартово объединение), на всех поля, используемые для группировки, и все поля, используемые для сортировки.

Последней проблемой является статья HAVING. Вы не сможете использовать для этого индекс вообще, поскольку это рассчитанное значение. Если это запрос, который вы часто будете использовать в системе (т. Е. Не только для отчетов), вы можете подумать о добавлении поля, которое вы можете использовать в качестве флага для этой цели фильтрации. Всякий раз, когда вы задаете c_done_meetings.MEDONE_ATTEND = 'u' в любом из ваших запросов, вы также можете установить этот флаг для члена или пользователя или как это связано с тем, чтобы в поле WHERE было поле для фильтрации.

Кроме того, вы можете получить более высокую производительность, получив сокращенный список пользователей или членов с этим значением u в подзапросе и затем присоединитесь к этому подзадачу в виде таблицы.

EDIT:

Осмотрев фактическую структуру таблицы, я могу ясно видеть, где вам нужно добавить индексы. Мне также интересно, почему у вас есть таблицы c_users и c_members с тем же самым точным первичным ключом. Почему бы это не просто один стол?

+0

Да, я думаю, я продолжу это и сделаю это. Вместо того, чтобы вычислять сумму, я просто добавлю ее как столбец в пользовательскую таблицу. – Andrew121007

0

Некоторых вещей, которые всплывают на меня:

Вы использовать как довольно много. Попробуйте что-то сделать с вашим php-кодом, чтобы это не было необходимо. Например, mem_sex имеет ограниченное количество вариантов. Сделайте переднюю часть переключателем или выпадающим меню, чтобы вы отправили значение, в котором вы можете использовать = вместо того, чтобы нравится.

Два, если вы добавите sum() в предложение select и соответствующее предложение group by, оно должно работать быстрее. Это стоит того.

+0

Причина, по которой я использую, так это потому, что я хочу иметь возможность оставить ее пустой, я думал, что SQL будет быстрее PHP, я буду продолжать использовать PHP для построения запроса. – Andrew121007

+0

Если ваш sql говорит, где секс нравится?, И он остается пустым, что вы ожидаете, что ваш запрос вернется? Кроме того, я не имел в виду использование php для написания sql, я имел в виду использование php для назначения лучших параметров запроса. –

0

Вы можете denormalise вам таблицы и добавлять поля к c_members, которые представляют свой SUM (c_done_meetings.MEDONE_ATTEND = «и»)> = 1 Но вам необходимо обновить это поле всегда, при обновлении c_done_meetings (могут с помощью триггера)

Также старайтесь избегать условий LIKE. Use = insead (возможно, по крайней мере, для SEX)

+0

Как я уже сказал в другом комментарии, я использую LIKE, потому что иногда он пуст. Я мог бы пойти и сделать некоторые PHP-запросы, хотя. – Andrew121007

+0

Исключить условие в PHP, когда оно пустое, всегда быстрее, чем SQL. Поэтому, если вы исключаете все условия LIKE и преподают значение количества пропущенных встреч, ваш запрос должен занимать пару секунд макс. – Yaroslav