【问题标题】:Mysql not leveraging primary key in "select * from table where (col,col) in"Mysql没有利用“从表中选择*(col,col)in”中的主键
【发布时间】:2011-03-09 22:28:01
【问题描述】:

我正在尝试运行此查询:

select * from matrix where (id1, id2) in ((1,2), (3,5));

但它非常慢。 (id1,id2) 是一个主键,所以这应该是一个快速查找。查询计划器是否失败?

解释说:

|  1 | SIMPLE      | s1_movie | ALL  | NULL          | NULL | NULL    | NULL | 48768876 | Using where |

其中 48768876 是它扫描的行数。

如果我只在“in”中搜索 1 个项目,我会在说明中得到 rows=1,这是正确的,因为它应该只是一个查找。

这是表格:

CREATE TABLE s1_movie (
   id1 INT NOT NULL,
   id2 INT NOT NULL,
   freq INT NOT NULL,
   diff FLOAT NOT NULL,
   PRIMARY KEY (id1, id2)
) ENGINE=INNODB;

我将如何做到这一点?查询计划器似乎失败了。

谢谢,

乔恩

【问题讨论】:

  • 这有点骇人听闻,但您可以使用高效的SELECTs 的UNION,例如(SELECT * FROM matrix WHERE id1 = 1 AND id2 = 2) UNION (SELECT * FROM matrix WHERE id1 = 3 AND id2 = 5)
  • 为什么matrix 变成了s1_movie ?

标签: mysql sql performance


【解决方案1】:

您可以将 WHERE 拆分为两个单一查找部分 ORed 在一起,但如果您不总是有两个选项,那将变得难以管理。

【讨论】:

    【解决方案2】:

    讨论示例

    CREATE TABLE s1_movie (
       id1 INT NOT NULL,
       id2 INT NOT NULL,
       freq INT NOT NULL,
       diff FLOAT NOT NULL,
       PRIMARY KEY (id1, id2)
    ) ENGINE=INNODB;
    
    insert into s1_movie select 1,2,3,4;
    insert into s1_movie select 1,3,3,4;
    insert into s1_movie select 1,4,3,4;
    insert into s1_movie select 1,5,3,4;
    insert into s1_movie select 1,6,3,4;
    insert into s1_movie select 1,7,3,4;
    insert into s1_movie select 1,8,3,4;
    insert into s1_movie select 1,9,3,4;
    insert into s1_movie select 1,0,3,4;
    insert into s1_movie select 2,2,3,4;
    insert into s1_movie select 2,3,3,4;
    

    比较

    explain extended
    select * from s1_movie where (id1, id2) = (1,2) or (id1,id2) = (3,5);
    

    和

    explain extended
    select * from s1_movie where (id1, id2) in ((1,2), (3,5));
    

    元组很漂亮不是吗? MySQL 可以很好地处理元组,尽管 Mark 的回答猜测是问题所在。问题在于 IN 子句。

    【讨论】:

    • @cinqoTimo 请扩展该评论​​,为什么它“仍然很慢”?它执行的计划与您的 UNION 完全相同(应该是 UNION ALL btw)
    • Richard - 我的错,我查看了错误的查询。你重写了语法,它是最后一个 sn-p 所以我认为这就是你的答案。
    【解决方案3】:

    问题在于您执行 IN() 语句的方式。 “IN”为“OR”语句提供了另一种语法。这样做的问题是它强制进行全表扫描,这不允许您的索引完成它们的工作。

    相反,将其分解为更小的 SELECT 语句并使用 UNION 来汇总您的结果。这将使您的索引更加相关。

    从您编写示例的方式来看,我无法完全判断您在做什么,但是像这样:

    SELECT * FROM matrix WHERE col1 = var1 AND col2 = var2
    UNION
    SELECT " FROM matrix WHERE col1 = var3 AND col2 = var4
    

    【讨论】:

      猜你喜欢
      • 2021-05-06
      • 1970-01-01
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-23
      • 2013-11-20
      相关资源
      最近更新 更多