【问题标题】:mysql query performancemysql查询性能
【发布时间】:2009-07-29 17:27:33
【问题描述】:

有人可以提示一下吗? :

我有一个表,比如说 tblA,其中我有 id1 和 id2 作为列和索引(id1,id2)。 我想选择 id2 属于几组的 id1。所以我想说

select id1 from tblA 
where id2 in (val1,val2,val3 ...)
union
select id1 from tblA 
where id2 in (val4,val2,val3 ...)
union
(...)*

假设我们在表 A 中有以下内容:

(1,1)
(1,2)
(1,3)
(1,4)
(1,5)
(2,1)
(2,2)
(2,3)

现在我想要所有具有id2 in (3,4)id1s。

所以我想得到的是id1 = 1

2 不应出现,因为虽然我们有一个关系 (2,3),但我们没有 (2,4)

任何想法如何执行此查询?我猜如果 (...) 增长太多,上面的方法会出现性能问题!?谢谢。

问候

【问题讨论】:

  • 好的,所以我将尝试用一个例子来解释它。我尝试了您的两个查询,但不是我想要的。假设我们在表 A 中有以下内容:(1,1),(1,2),(1,3),(1,4),(1,5),(2,1),(2, 2),(2,3)。现在我想要所有在(3,4)中具有 id2 的 id1。所以我想得到它的id1s =“1”。 “2”不应该出现,因为尽管我们有一个关系(2,3)我们没有(2,4)。我说清楚了吗?这有点难以解释......无论如何,谢谢
  • 只是出于好奇,为什么? :) 下面有几个答案看起来可以正常工作。哪一个最有意义,如果没有为什么其他东西可能对您更好,就无法回答?如果事情不经常改变,您可以用大量查询填写您的列表,然后更新它们。然后,您的答案将是即时的。创建一个只有 id1 和一个布尔值的简单临时表可以帮助您过滤每个集合(即在每次传递中找到匹配的那些)。

标签: sql performance mysql


【解决方案1】:

你应该像这样创建一个临时表:

CREATE TABLE temp (id INT NOT NULL PRIMARY KEY) ENGINE MEMORY;

,用您正在搜索的值填充它(在您的示例中为23):

INSERT
INTO    temp
VALUES  (3), (4)

并发出以下查询:

SELECT  ad.id1
FROM    (
        SELECT  DISTINCT id1
        FROM    a
        ) ad
WHERE   NOT EXISTS
        (
        SELECT  NULL
        FROM    temp
        WHERE   NOT EXISTS
                (
                SELECT  NULL
                FROM    a
                WHERE   a.id1 = ad.id1
                        AND a.id2 = temp.id
                )
        )

您应该在(id1, id2) 上创建一个复合索引才能使其正常工作。

对于每个id1,这将对每个id2 最多探测一次temp,并且一旦为每个id1 找到temp 中缺少的第一个id2,就会返回false。

这是查询计划:

1, 'PRIMARY', '<derived2>', 'ALL', '', '', '', '', 2, 'Using where'
3, 'DEPENDENT SUBQUERY', 'temp', 'ALL', '', '', '', '', 2, 'Using where'
4, 'DEPENDENT SUBQUERY', 'a', 'eq_ref', 'PRIMARY', 'PRIMARY', '8', 'ad.id1,test.temp.id', 1, 'Using index'
2, 'DERIVED', 'a', 'range', '', 'PRIMARY', '4', '', 3, 'Using index for group-by'

,没有temporary,没有filesort

【讨论】:

    【解决方案2】:

    工会会扼杀你的表现。使用这样的东西:

    select id1 from tblA where id2 in (val1,val2,val3 ...) or id2 in (val4,val2,val3)
    

    【讨论】:

    • 您的意思是您想要所有 id1 值,其中 id2 在每个子集中(您的措辞似乎表明了这一点,但示例查询不会这样完成)。如果是这种情况,您只需将 where 子句中的“或”更改为“和”。
    • 请查看我上面的评论,我不是那个意思
    【解决方案3】:

    你能把所有的集合组合成一个大集合吗?

    如果顺序不重要,这似乎是最快的方式。

    【讨论】:

      【解决方案4】:

      首先,记住这一点

      select id1 from tblA where id2 in (val1, val2, val3) union
      select id1 from tblA where id2 in (val4, val5, val6)
      

      应该给出与

      相同的结果
      select id1 from tblA where id2 in (val1, val2, val3, val4, val5, val6)
      

      因此您也许可以通过制定单个查询而不是使用联合来提高效率。

      其次(并且独立于上述),您应该将 id2 上的索引添加到 tblA。如果没有它,id2 值会随机分布在现有索引和表数据中,因此优化器将别无选择,只能对索引执行线性扫描,如果幸运的话。

      【讨论】:

        【解决方案5】:

        但是所有这些查询都会返回列 id1 中的两个 id!我认为罗伯特的意思是他只想要列 id1 中的“1”:

           id1 id2
            1 | 1
            1 | 2
            1 | 3
            1 | 4  -->  id1s that have id2 with 3 and 4
            1 | 5
            2 | 1
            2 | 2
            2 | 3
        

        因为 id1=2 没有 3 AND 4 它不应该是结果。

        如果我误解了,请纠正我... 我试图做一个声明,但我不能只取回 id1=1,但我也对有效的解决方案非常感兴趣!

        【讨论】:

          【解决方案6】:

          您需要在“id2”列上创建单独的索引,因为仅在查找 id2 时不会使用 (id1,id2) 上的组合索引。

          此查询执行您提到的操作

          SELECT id1 FROM tblA WHERE id2 IN (?,?,?,?)
          GROUP BY id1 HAVING COUNT(id2)=4
          

          注意:您需要将 HAVING 子句中的 COUNT(id2) 条件调整为 IN 子句中提到的值的数量。这里我用了四个“?”表示四个值,这就是我写 COUNT(id2)=4 的原因。

          对于您在评论中提到的场景,查询将如下所示

          SELECT id1 FROM tblA WHERE id2 IN (3,4)
          GROUP BY id1 HAVING COUNT(id2)=2
          

          【讨论】:

            猜你喜欢
            • 2011-05-06
            • 2011-10-23
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-10-13
            • 2016-03-09
            相关资源
            最近更新 更多