2015-04-25 95 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 

“解释” 返回以下内容:为什么不使用第2场

*************************** 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 

idx_clin_eventdate_medcode,即(patid,eventdate),但只有patid(请参阅ref列)?

如果我改变where条件的平等,它工作正常:

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中DESCASC运营商无操作不幸的是(与每一个版本的MySQL高达5.7至少)。因此,除非您可以反转查询(使用>而不是<),否则MySQL无法有效使用索引。

请注意,它可能会更快,不使用索引,它取决于具体情况。由于只有171行,我不会太担心。

+0

谢谢,这是我试图改进的更复杂查询的一小部分,因为它非常慢。我试图使用>而不是<作为实验,但它并不使用完整的索引。 – Antonella

+0

如果可能,我会强烈建议升级到PostgreSQL,它会更好地处理复杂的查询。在mysql中,通常最好保持查询尽可能简单。 – Wolph

+0

谢谢,现在不可能。甚至以下简单查询具有同样的问题:SELECT p.patid,从患者c1.eventdate 为p 左加入op_adv_effects._clinical作为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) FROM op_adv_effects._clinical WHERE patid = p.patid AND EVENTDATE> p.case_index )AS EVENTDATE FROM患者为P; – Antonella

+0

嗯...你可以展示查询的EXPLAIN吗? (包括我发布的新版本) –

+0

我在问题的末尾添加了EXPLAIN。谢谢 – Antonella

相关问题