2015-04-25 6 views
1

Не могли бы вы помочь мне с этим запросом, пожалуйста?Почему этот запрос MySQL не использует полный индекс?

SELECT p.patid, MAX(c1.eventdate) as eventdate 
from patient as p 
left join op_adv_effects._clinical as c1 on p.patid = c1.patid 
where c1.eventdate < p.case_index 
group by p.patid 

Вот вывод SHOW CREATE TABLE для 2-х таблиц:

patient CREATE TABLE `patient` (
    `patid` int(10) unsigned NOT NULL, 
    `case_index` date NOT NULL, 
    PRIMARY KEY (`patid`,`case_index`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs 

_clinical CREATE TABLE `_clinical` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `patid` int(10) unsigned NOT NULL, 
    `eventdate` date NOT NULL, 
    `medcode` mediumint(8) unsigned DEFAULT NULL, 
    `adid` mediumint(8) unsigned DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_clin_eventdate_medcode` (`patid`,`eventdate`,`medcode`), 
    KEY `idx_clin_eventdate_adid` (`patid`,`eventdate`,`adid`) 
) ENGINE=InnoDB AUTO_INCREMENT=62407536 DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs 

"объяснить" возвращает следующее:

*************************** 1. row ******************** 
      id: 1 
    select_type: SIMPLE 
     table: p 
     type: index 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 7 
      ref: NULL 
     rows: 182939 
     Extra: Using index 
*************************** 2. row ******************** 
      id: 1 
    select_type: SIMPLE 
     table: c1 
     type: ref 
possible_keys: idx_clin_eventdate_medcode,idx_clin_eventdate_adid 
      key: idx_clin_eventdate_medcode 
     key_len: 4 
      ref: gprd_opadveff_extra_elisa.p.patid 
     rows: 171 
     Extra: Using where; Using index 

Почему не используя первые 2 поля idx_clin_eventdate_medcode, т. е. (patid, eventdate), но только patid (см. столбец ref)?

Если я изменяю где условие равенства, то он работает отлично:

SELECT p.patid, MAX(c1.eventdate) as eventdate 
from patient as p 
left join op_adv_effects._clinical as c1 on p.patid = c1.patid 
where c1.eventdate = p.case_index 
group by p.patid 

*************************** 1. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: p 
     type: index 
possible_keys: PRIMARY 
      key: PRIMARY 
     key_len: 7 
      ref: NULL 
     rows: 182939 
     Extra: Using index 
*************************** 2. row *************************** 
      id: 1 
    select_type: SIMPLE 
     table: c1 
     type: ref 
possible_keys: idx_clin_eventdate_medcode,idx_clin_eventdate_adid 
      key: idx_clin_eventdate_medcode 
     key_len: 7 
      ref: gprd_opadveff_extra_elisa.p.patid,gprd_opadveff_extra_elisa.p.cas 
e_index 
     rows: 1 
     Extra: Using index 

Одинаковые результаты для некоторых предлагаемых вариант:

explain SELECT patid, 
(SELECT eventdate 
FROM op_adv_effects._clinical 
WHERE patid = p.patid 
AND eventdate < p.case_index 
ORDER BY eventdate DESC 
LIMIT 1) AS eventdate 
FROM patient AS p; 

*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: p 
     type: index 
possible_keys: NULL 
      key: PRIMARY 
     key_len: 7 
      ref: NULL 
     rows: 182939 
     Extra: Using index 
*************************** 2. row *************************** 
      id: 2 
    select_type: DEPENDENT SUBQUERY 
     table: _clinical 
     type: ref 
possible_keys: idx_clin_eventdate_medcode,idx_clin_eventdate_adid 
      key: idx_clin_eventdate_medcode 
     key_len: 4 
      ref: gprd_opadveff_extra_elisa.p.patid 
     rows: 171 
     Extra: Using where; Using index; Using filesort 


explain SELECT patid, 
(SELECT MAX(eventdate) 
FROM op_adv_effects._clinical 
WHERE patid = p.patid 
AND eventdate < p.case_index) AS eventdate 
FROM patient AS p; 

*************************** 1. row *************************** 
      id: 1 
    select_type: PRIMARY 
     table: p 
     type: index 
possible_keys: NULL 
      key: PRIMARY 
     key_len: 7 
      ref: NULL 
     rows: 182939 
     Extra: Using index 
*************************** 2. row *************************** 
      id: 2 
    select_type: DEPENDENT SUBQUERY 
     table: _clinical 
     type: ref 
possible_keys: idx_clin_eventdate_medcode,idx_clin_eventdate_adid 
      key: idx_clin_eventdate_medcode 
     key_len: 4 
      ref: gprd_opadveff_extra_elisa.p.patid 
     rows: 171 
     Extra: Using where; Using index 

Запросом является частью более сложного, представлены ниже , Однако это всего лишь один пример нескольких сложных запросов, которые должны использовать недостающую часть индекса в eventdate. По этой причине это очень важно.

CREATE TABLE bmi_lp 
(PRIMARY KEY (patid)) 
ENGINE=INNODB DEFAULT CHARSET=latin1 COLLATE=latin1_general_cs 
SELECT tmp.patid, a2.data3 as bmi_lp, tmp.eventdate as bmi_lp_date 
from ( 
SELECT p.patid, MAX(c.eventdate) as eventdate 
from patient as p 
left join op_adv_effects._clinical as c1 on p.patid = c1.patid 
left join op_adv_effects._additional as a1 on c1.patid = a1.patid 
where c1.adid <> 0 and c1.adid = a1.adid 
and a1.enttype = 13 
and a1.data3 is not null 
and c1.eventdate < p.case_index 
group by p.patid 
order by p.patid) as tmp 
left join op_adv_effects._clinical as c2 on tmp.patid = c2.patid 
left join op_adv_effects._additional as a2 on c2.patid = a2.patid 
where tmp.eventdate = c2.eventdate and c2.adid = a2.adid 
+0

Обратите внимание, что этот запрос отображается как INNER JOIN – Strawberry

ответ

1

Благодаря WHERE вы делаете INNER JOIN прямо сейчас. Вы это намеревались?


Несмотря на это, из-за < индекс не может быть использован прямо сейчас, если вы имели индекс, который будет использовать другой порядок он мог бы работать.

Например, в PostgreSQL вы могли бы сделать это:

CREATE INDEX idx_clin_eventdate_medcode ON _clinical (patid ASC, eventdate DESC); 

В MySQL в DESC и ASC операторы не являются оп, к сожалению (с каждой версией MySQL до 5.7, по крайней мере). Поэтому, если вы не можете отменить запрос (используйте > вместо <), MySQL не может эффективно использовать этот индекс.

Обратите внимание, что это может быть даже быстрее, чем использовать индекс, это зависит от случая. Поскольку это происходит только через 171 строку, я бы не стал слишком беспокоиться.

+0

Спасибо, это небольшая часть более сложного запроса, который я пытаюсь улучшить, поскольку он очень медленный. Я попытался использовать> вместо <в качестве эксперимента, но он все равно не использует полный индекс. – Antonella

+0

Если это вообще возможно, я настоятельно рекомендую обновить PostgreSQL, он будет обрабатывать сложные запросы намного лучше.Внутри mysql обычно лучше всего держать запросы как можно проще. – Wolph

+0

Спасибо, сейчас это невозможно. Даже простой запрос имеет те же проблемы: SELECT p.patid, c1.eventdate от пациента, р покинул присоединиться op_adv_effects._clinical, как c1 на p.patid = c1.patid где c1.eventdate> p.case_index – Antonella

0

Дайте это попробовать: (. Нет GROUP BY требуется)

SELECT patid, 
     (SELECT MAX(eventdate) 
      FROM op_adv_effects._clinical 
      WHERE patid = p.patid 
       AND eventdate < p.case_index 
    ) AS eventdate 
    FROM patient AS p; 

Вот вариант, который использует LIMIT 1 вместо MAX:

SELECT patid, 
     (SELECT eventdate 
      FROM op_adv_effects._clinical 
      WHERE patid = p.patid 
       AND eventdate < p.case_index 
      ORDER BY eventdate DESC 
      LIMIT 1 
    ) AS eventdate 
    FROM patient AS p; 

Сколько строк в выводе ?

+0

Спасибо, хорошее предложение, но, к сожалению, никакого улучшения .. Я также пробовал с SELECT patid, (SELECT MIN (EVENTDATE) ОТ op_adv_effects._clinical ГДЕ patid = p.patid И EVENTDATE> p.case_index ) КАК EVENTDATE от пациента AS р; – Antonella

+0

Хммм ... Не могли бы вы показать EXPLAIN для запросов? (в том числе новый, который я опубликовал) –

+0

Я добавил EXPLAINs в конце моего вопроса. Спасибо – Antonella

Смежные вопросы