[英]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(*)
是一件坏事,它将被扩展到所需字段的完整列表。 但是,上面未列出的字段是更多int
和double
。 还有那些被退回的另一个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执行此操作的最有效方法。
但是我最大的提示是:
每次都是一样的〜560 id吗? 还是在不同的查询运行中使用不同的〜500 id?
您可以将560个UserID插入单独的表(甚至临时表)中,在该表上粘贴索引,然后将其内部连接到原始表。
这是您最重要的查询吗? 这是交易表吗?
如果是这样,请尝试在user_id上创建聚簇索引。 您的查询可能很慢,因为即使找到匹配的记录(在user_Id索引上进行索引查找),它仍然必须随机读取磁盘以检索列(键查找)。
如果无法更改聚簇索引,则可能需要考虑ETL流程(最简单的方法是将触发器插入具有最佳索引的另一个表中)。 这将产生更快的结果。
还要注意,如此大的查询可能需要一些时间来解析,因此如果可能的话,可以通过将查询到的ID放入临时表中来解决问题
您可以尝试在临时表中插入需要查询的ID,并内部联接两个表。 我不知道这是否有帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.