繁体   English   中英

在MySQL中使用集的更快方法

[英]faster way to use sets in MySQL

我有一个具有以下结构的MySQL 5.1 InnoDB表( customers ):

int         record_id (PRIMARY KEY)
int         user_id (ALLOW NULL)
varchar[11] postcode (ALLOW NULL)
varchar[30] region (ALLOW NULL)
..
..
..

表格中大约有700万行。 当前,正在按以下方式查询表:

SELECT * FROM customers WHERE user_id IN (32343, 45676, 12345, 98765, 66010, ...

在实际查询中, IN子句中当前有560个以上的user_id 由于表中有几百万条记录,因此此查询速度

表上有二级索引,第一个位于user_id本身,我认为这会有所帮助。

我知道SELECT(*)是一件坏事,它将被扩展到所需字段的完整列表。 但是,上面未列出的字段是更多intdouble 还有那些被退回的另一个50,但他们需要的报告。

我想有一种更好的方法来访问user_id的数据,但是我不知道该怎么做。 我的最初反应是删除user_id字段上的ALLOW NULL ,因为我了解NULL处理会减慢查询速度?

如果您能指出比使用IN ( )方法更有效的方向,我将不胜感激。

编辑然解释,说:

select_type = SIMPLE 
table = customers 
type = range 
possible_keys = userid_idx 
key = userid_idx 
key_len = 5 
ref = (NULL) 
rows = 637640 
Extra = Using where 

有帮助吗?

首先,检查USER_ID上是否有索引, 并确保已使用

您可以通过运行EXPLAIN

其次,创建一个临时表并在JOIN使用它:

CREATE TABLE temptable (user_id INT NOT NULL)

SELECT  *
FROM    temptable t
JOIN    customers c
ON      c.user_id = t.user_id

第三,查询如何返回行?

如果它返回几乎所有行,那么它将很慢,因为它首先必须通过连接通道泵送所有这几百万个数据。

NULL不会减慢查询速度,因为IN条件仅满足索引的非NULL值。

更新:

使用索引,该计划是好的,除了它返回超过一百万行。

您是否真的需要将所有这638,000行放入报告中?

希望它不会被印出来:对雨林,全球变暖和其他事物有害。

认真地说,您似乎需要对查询进行聚合或分页。

“选择*”并不像某些人想象的那样糟糕。 基于行的数据库将提取整行,因此在不使用覆盖索引的情况下,“ SELECT *”从本质上来讲不会比“ SELECT a,b,c”慢(注意:当您有较大的BLOB时,有时是一个例外,但这是一个极端的情况。

首先,您的数据库是否适合RAM? 如果没有,请获取更多的RAM。 不,认真 现在,假设您的数据库太大而无法合理地放入ram(例如,> 32Gb),那么您应该尝试减少随机I / O的数量,因为它们可能会使事情停滞不前。

从这里开始,我假设您正在使用带有RAID1(或RAID10等)中的RAID控制器和至少两个主轴的适当服务器级硬件。 如果不是,请离开并获取该信息。

您绝对可以考虑使用聚集索引。 在MySQL InnoDB中,您只能对主键进行集群,这意味着如果当前主键有其他内容,则必须对其进行更改。 复合主键是可以的,并且如果您要对一个条件(例如user_id)进行大量查询,则将其设为主键的第一部分无疑是有好处的(您需要添加其他内容才能使其成为主键)独特)。

或者,您可以使查询使用覆盖索引,在这种情况下,您不需要user_id作为主键(实际上,不必这样)。 仅当您需要的所有列都在以user_id开头的索引中时,才会发生这种情况。

就查询效率而言,WHERE user_id IN(大ID列表)几乎可以肯定是从SQL执行此操作的最有效方法。

但是我最大的提示是:

  • 牢记目标,找出目标,并在达到目标时停止。
  • 不要相信任何人的话-试试看
  • 确保您的性能测试系统与生产的硬件规格相同
  • 确保性能测试系统的数据大小和种类与生产相同(相同的架构还不够好!)。
  • 如果无法使用生产数据,则使用合成数据(复制生产数据在逻辑上可能会很困难(请记住您的数据库> 32Gb);这也可能违反安全策略)。
  • 如果您的查询是最佳的(可能已经是最佳查询),请尝试调整架构,然后调整数据库本身。

每次都是一样的〜560 id吗? 还是在不同的查询运行中使用不同的〜500 id?

您可以将560个UserID插入单独的表(甚至临时表)中,在该表上粘贴索引,然后将其内部连接到原始表。

这是您最重要的查询吗? 这是交易表吗?

如果是这样,请尝试在user_id上创建聚簇索引。 您的查询可能很慢,因为即使找到匹配的记录(在user_Id索引上进行索引查找),它仍然必须随机读取磁盘以检索列(键查找)。

如果无法更改聚簇索引,则可能需要考虑ETL流程(最简单的方法是将触发器插入具有最佳索引的另一个表中)。 这将产生更快的结果。

还要注意,如此大的查询可能需要一些时间来解析,因此如果可能的话,可以通过将查询到的ID放入临时表中来解决问题

您可以尝试在临时表中插入需要查询的ID,并内部联接两个表。 我不知道这是否有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM