我需要解决以下任务:我在PHP脚本中有一个非常大的ID数组,我需要从MySQL数据库中选择ID NOT IN 这个数组的所有行。
有几个类似的问题(How to find all records which are NOT in this array? (MySql)),最喜欢的答案是在括号内使用NOT IN ()
implode(',',$array)
构建。
这很有效......直到我的阵列长达2007 ID和大约20 kB(在我的情况下)我有一个“ MySQL服务器已经消失”错误。据我所知,这是因为冗长的查询。
这个问题还有一些解决方案:
SET GLOBAL max_allowed_packet=1073741824;
(刚刚从this问题中获取)。
我可能会以这种方式做到这一点,但是现在我怀疑NOT IN (implode)
方法对于一个大数组来说是个好方法(我希望在我的情况下,数组最多可以有8000个ID和100个kB)。
对于大型阵列有没有更好的解决方案?
谢谢!
编辑1
作为解决方案,建议将所有ID从数组插入临时表,然后使用JOIN解决初始任务。这很清楚。但是我从来没有使用临时表,因此我还有一些额外的问题(可能值得作为一个单独的问题,但我决定将其保留在这里):
如果我需要在一次MySQL会话期间多次执行此例程,哪种方法会更好:
每次我需要 SELECT ID NOT IN PHP数组我将创建一个新的临时表(所有这些表将在MySQL连接终止后删除 - 在我的脚本终止之后事实)。
我将创建一个临时表,并在我需要SELECT
之后我将TRNCATE临时表。
哪个更好?或者我错过了其他什么?
答案 0 :(得分:3)
在这种情况下,通常最好创建一个临时表并对其执行查询。它有以下几点:
CREATE TEMPORARY TABLE t1 (a int);
INSERT INTO t1 VALUES (1),(2),(3);
SELECT * FROM yourtable
LEFT JOIN t1 on (yourtable.id=t1.a)
WHERE t1.a IS NULL;
当然应该构造INSERT
语句,以便将数组中的所有值都插入到临时表中。
编辑:在单个INSERT
语句中插入所有值很可能会导致您遇到的同样问题。因此,我建议你使用prepared statement来执行,以便在迭代PHP数组时将数据插入到临时表中。
答案 1 :(得分:1)
我曾经不得不解决这个问题,但使用IN(id)
WHERE条款,大约有20,000-30,000个标识符(indexes
)。
我使用SELECT
查询解决这个问题的方法是减少过滤后的标识符数量并增加发送相同查询的次数,以便提取相同的数据。
您可以将array_chunk
用于PHP并将20,000
除以15
,这将为您提供15
单独的SQL调用,按1500
标识符过滤记录(每次通话,您可以划分超过15
以进一步减少identifiers
的数量。但在您的情况下,如果您只是将2007
标识符除以10
,则会减少每个SQL请求将数据库推送到200
的标识符数量,还有其他方式用临时表进一步优化这一点,所以第四。
通过划分您尝试过滤的索引数量,它将加快每个查询的速度,比在单个转储中将每个索引发送到数据库的速度更快。