【问题标题】:Optimise query to determine of a value is between a min and max value优化查询以确定一个值在最小值和最大值之间
【发布时间】:2014-03-25 13:05:23
【问题描述】:

我有一个包含最小值和最大值字段的表格。该表填充了 200 条记录,这些记录都包含这些最小值和最大值的范围。我需要确定给定值是否在其中一个范围内。

示例

min | max    
21  | 34    
64  | 83    
112 | 134

给定值:36。在这种情况下,查询不应该找到任何东西。

当然,我可以遍历每条记录并查询值是否介于这些值之间,但是查询每分钟会运行几次,所以我想知道如何优化它。

【问题讨论】:

  • 这张表有哪些索引?
  • a) 您的查询目前是什么样的? b) 您是否根据合理的实时数据集对其进行了基准测试以确定其性能? c) 我相信关于优化的问题应该在 codereview.stackexchange.com 上而不是在这里。

标签: php mysql


【解决方案1】:

这就是 RDBMS 的工作方式 - 它遍历行。对于现代数据库来说,200 条记录实际上不算什么。

无论如何,要优化这一点,您应该在这些列上创建一个索引。 两个列上的一个索引。

然后像下面这样的简单查询将使用这个索引并且即使有很多行也可以非常快速地工作。

SELECT * from table where 36 between min and max;

【讨论】:

  • +1 表示“200 条记录实际上对现代数据库来说不算什么”
【解决方案2】:

在 min 和 max 列上创建索引应该可以提高性能

【讨论】:

    【解决方案3】:

    between 运算符可以满足您的需要:

    SELECT * FROM table WHERE 36 BETWEEN min AND max;
    

    【讨论】:

      【解决方案4】:

      两列上的索引并没有特别的帮助。您要查找的查询是:

      select *
      from minmax 
      where "min" <= 36 and "max" >= 36;
      

      不幸的是,这有两个不等式;索引实际上只能利用其中一个不等式。因此,将"max" 放入索引确实 会有所帮助,但这只是因为索引“覆盖”了查询。即索引可用于处理查询,无需参考原始数据页。

      但是,由于表中只有 200 行,处理并不是特别繁重。如果您想知道表中是否存在某些内容,我建议您使用以下查询:

      select (case when exists (select 1 from minmax where "min" <= 36 and "max" >= 36)
                   then 1
                   else 0
              end)
      

      我的猜测是,在这么小的表上的性能与minmax(min)minmax(min, max) 上的索引几乎相同。对于大表,复合索引会更好。

      【讨论】:

        【解决方案5】:

        这是一个与GeoIP table join with table of IP's in MySQL 非常相似的问题。人们在 MySQL 表中查找 GeoIP 信息很常见,最快的方法是使用空间索引。

        基本想法是使用包含表中最小值和最大值的数据创建一个多边形,然后向该字段添加空间索引。最后使用MBRCONTAINS(),您可以非常快速有效地查看一个点是否在集合内。

        这里有一篇文章描述了如何做到这一点:http://blog.jcole.us/2007/11/24/on-efficiently-geo-referencing-ips-with-maxmind-geoip-and-mysql-gis/

        基本思想是创建一个像这样的多边形:

        SET poly = GEOMFROMWKB(POLYGON(LINESTRING(
            POINT(min,-1),
            POINT(max,-1),
            POINT(max,1),
            POINT(min,1),
            POINT(min,-1)
        )));
        

        然后去查找使用

        SELECT id
        FROM your_table
        WHERE MBRCONTAINS(ip_poly, POINTFROMWKB(POINT([SEARCH_NUMBER], 0)))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-10-24
          • 1970-01-01
          • 1970-01-01
          • 2015-03-28
          • 2015-02-03
          • 1970-01-01
          • 1970-01-01
          • 2021-04-07
          相关资源
          最近更新 更多