【问题标题】:MariaDB: No selection using EXISTS if column has an indexMariaDB:如果列有索引,则不使用 EXISTS 进行选择
【发布时间】:2020-11-23 17:29:51
【问题描述】:

我第一次在使用 EXISTS 时遇到了一个我没有想到的问题。我有一张包含患者 ID 和咨询日期的表格,并尝试选择具有相同咨询日期的多条记录的患者:

-- total rows in vital: 732,527
-- number of rows after selection: 7,817
-- number of rows with multiple pat_id/kons_dt: 809
SELECT a.*
FROM emr.vital a
WHERE EXISTS (SELECT 1
              FROM (SELECT pat_id, kons_dt, COUNT(*)
                    FROM emr.vital b
                    GROUP BY pat_id, kons_dt
                    HAVING COUNT(*) > 1
                ) b
               WHERE a.pat_id = b.pat_id
          )

这给了我以下结果(只有前 4 行):

+--------+---------------+
| pat_id | kons_dt       |
+--------+---------------+
|  21384 | 2018-06-29    |
|  21384 | 2018-06-29    |
|  21888 | 2017-04-04    |
|  21888 | 2017-04-04    |
|  ...   | ...           |
+--------+---------------+

emr.vital没有索引。如果我添加一个索引:

CREATE INDEX id ON emr.vital(pat_id);

并运行相同的代码没有选择记录。我尝试创建一个最小示例,但没有成功获得相同的结果,也就是说,无论有无索引,我都得到了相同的结果。

也许 EXPLAIN 摘录可以提供一些想法:

无索引:

+----+--------------+-------------+--------+---------------+--------------+---------+-----------+--------+---------------------------------+
| id | select_type  |    table    |  type  | possible_keys |     key      | key_len |    ref    |  rows  |              Extra              |
+----+--------------+-------------+--------+---------------+--------------+---------+-----------+--------+---------------------------------+
|  1 | PRIMARY      | a           | ALL    | \N            | \N           | \N      | \N        | 734988 | Using filesort                  |
|  1 | PRIMARY      | <subquery2> | eq_ref | distinct_key  | distinct_key | 7       | func,func |      1 |                                 |
|  2 | MATERIALIZED | <derived3>  | ALL    | \N            | \N           | \N      | \N        | 734988 |                                 |
|  3 | DERIVED      | b           | ALL    | \N            | \N           | \N      | \N        | 734988 | Using temporary; Using filesort |
+----+--------------+-------------+--------+---------------+--------------+---------+-----------+--------+---------------------------------+

带索引:

+----+-----------------+-------------+--------+---------------+--------------+---------+----------------------------+--------+----------------------------------------------+
| id |   select_type   |    table    |  type  | possible_keys |     key      | key_len |            ref             |  rows  |                    Extra                     |
+----+-----------------+-------------+--------+---------------+--------------+---------+----------------------------+--------+----------------------------------------------+
|  1 | PRIMARY         | a           | ALL    | pat_id        | \N           | \N      | \N                         | 734988 | Using filesort                               |
|  1 | PRIMARY         | <subquery2> | eq_ref | distinct_key  | distinct_key | 4       | func                       |      1 |                                              |
|  2 | MATERIALIZED    | <derived3>  | ALL    | \N            | \N           | \N      | \N                         | 734988 |                                              |
|  3 | LATERAL DERIVED | b           | ref    | pat_id        | pat_id       | 5       | emr.a.pat_id               |      1 | Using where; Using temporary; Using filesort |
+----+-----------------+-------------+--------+---------------+--------------+---------+----------------------------+--------+----------------------------------------------+

感谢任何帮助。 MariaDB 版本:10.4.8。

编辑1:这是pat_id上没有索引的原始表的结构。

CREATE TABLE `vital` (
  `pat_id`        int(10) unsigned DEFAULT NULL,
  `kons_dt`       date DEFAULT NULL,
  `praxis_id`     int(10) unsigned DEFAULT NULL,
  `sex`           varchar(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `doby`          smallint(6) DEFAULT NULL,
  `age_y`         smallint(6) DEFAULT NULL,
  `gewicht`       double DEFAULT NULL,
  `groesse`       double DEFAULT NULL,
  `bmi`           double DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

【问题讨论】:

  • exists 的选择可以减少,因为您不需要该表中的任何数据
  • 请提供SHOW CREATE TABLE vital;
  • 这会加快查询速度:INDEX(pat_id, kons_dt),也许会显着。
  • @Rick James:我添加了表格结构和表格行数以及选择。关于加速:谢谢。然而,这不是速度问题,而是向 pat_id 添加索引或组合 pat_id/kons_dt 选择不起作用。如果我删除索引,我会得到预期的结果。这是一个从未遇到过的奇怪行为,因为索引应该加速并且不干扰选择逻辑。
  • 您说要添加INDEX(id),但表格中没有id。请澄清。

标签: mysql indexing mariadb exists


【解决方案1】:

你有一个谜。如果您可以创建一个显示问题的小型数据集(并且没有敏感信息),请提交错误报告。

同时,试试这个:

SELECT  a.*
    FROM ( SELECT  DISTINCT pat_id
            FROM ( SELECT  pat_id, kons_dt
                    FROM  emr.vital b
                    GROUP BY  pat_id, kons_dt
                    HAVING  COUNT(*) > 1 
                 ) b
         ) c
    JOIN  emr.vital a USING(pat_id)
    WHERE  a.pat_id = c.pat_id ;

并拥有INDEX(pat_id, kons_dt)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 2019-07-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多