【问题标题】:Optimize SELECT ... WHERE IN (...)优化 SELECT ... WHERE IN (...)
【发布时间】:2011-11-24 23:06:17
【问题描述】:

我从外部系统接收到一系列产品 ID。我必须显示保留序列的产品信息。

我正在使用以下选择:

SELECT * FROM  products
WHERE  prodid in (10331,11639,12127..) ORDER BY Field(prodid, 10331,11639,12127...);

序列可以包含 20 个 ID。 prodid 有 b-tree 索引。

这是非常频繁的查询,我正在努力寻找提高系统该部分性能的方法。现在这个查询的平均时间是 0.14-0.2 秒 我想将时间减少到 0.01-0.05 秒。

最好的方法是什么? MySQL HASH 索引,将产品 id 存储在 memcached 中,还是其他?

【问题讨论】:

  • prodid 列的数据类型是什么? IN 子句中通常有多少个产品 ID?
  • prodid 为 INT (prodid
  • 直接ID选择的数据之间是否有任何额外的关系?瓶颈可能在于每次查询跳过一个(可能很大的)数据库 20 次以选择微小的数据,因此通过其他一些参数对其进行聚类可能是一种选择。
  • 不,与其他表没有关系。如图所示,表格和 SELECT 很简单。外部系统完成所有繁重的工作 - 我只需要选择这些 ID 并显示产品信息。

标签: mysql performance memcached


【解决方案1】:
SELECT * FROM  products                         <<-- select * is non-optimal
WHERE  prodid in (10331,11639,12127..) 
ORDER BY Field(prodid, 10331,11639,12127...);   <<-- your problem is here

首先在prodid 上放置一个索引,请参阅@Anthony 的回答。

比将查询更改为:

SELECT only,the,fields,you,need FROM  products
WHERE  prodid in (10331,11639,12127..) 
ORDER BY prodid

如果您在将IN 子句提供给IN 子句之前确保您的IN 列表按升序排序,则order by prodid 将产生与order by field(... 相同的结果

  • 使用函数而不是字段会扼杀使用索引的任何机会,从而导致速度变慢。
  • select * 将获取您可能不需要的数据,从而导致额外的磁盘访问、额外的内存使用和额外的网络流量。
  • 在 InnoDB 上,如果您只有 select 索引字段,MySQL 将永远不会读取表,而只会读取索引节省时间(在您的情况下,这可能不是问题)

最好的方法是什么? MySQL HASH 索引,将产品 ID 存储在 memcached 中,还是其他?

您可以使用一些技巧。

  • 如果products表不是太大,可以做成memory表,存储在RAM中。不要对大桌子这样做,它会减慢其他事情的速度。
    您只能在内存表上使用hash 索引。
  • 如果prodid是连续的,你可以用BETWEEN 1000 AND 1019代替
    IN (1000, 1001 ..., 1019)

【讨论】:

  • 其实,ORDER BY Field - 不是一个函数,它是 MySQL 用于设置输出顺序的内部构造。这是一种仅保留输出顺序的方法。如果我跳过这个结构,产品信息将按随机顺序显示。
  • @Andre,你错了,请参阅我帖子中的最后一个编辑。始终在 order by 子句中使用列名,而不是函数。 Field() 是一个函数,看这里:dev.mysql.com/doc/refman/5.0/en/… (注意url中的function这个词)
  • 我无法按升序或以某种方式对 ID 进行排序 - 我必须保持产品的顺序。老实说,我并没有选择使用 * 的所有字段。所以,作为结论 - 我必须删除“按字段排序”并在我的软件中进行排序?
【解决方案2】:

您可以尝试创建结果的联合:

SELECT * FROM  products WHERE prodid = 10331
UNION ALL
SELECT * FROM  products WHERE prodid = 11639
UNION ALL
.
.
UNION ALL
SELECT * FROM  products WHERE prodid = 12127

【讨论】:

    【解决方案3】:

    您可以尝试使用以下查询在 prodid 列上放置索引:

    CREATE INDEX index_name
    ON products (prodid); 
    

    欲了解更多信息,请阅读this post.

    【讨论】:

    • prodid已经有b-tree索引了,我刚才提到了
    猜你喜欢
    • 1970-01-01
    • 2015-10-12
    • 2016-06-02
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多