使用 SQL、Numpy 或 Python 列表比较列、数组、列表

问题描述 投票:0回答:1

我有两个 SQL 表

tModel 有 9 列(ID、日期 N1、N2、N3、N4、N5、N6、Flag)和 3 亿行

tPairAP 有 3 列(ID、N1、N2)和 750 行

我需要执行的任务是查找 tModel 上 N1、N2、N3、N4、N5、N6 的任何行是否包含来自 tPairAP 的 N1 和 N2

尽管表很大,但我首先尝试使用以下代码在 SQL 中运行查询

WITH Subquery AS (
        SELECT t1.ID
        FROM tModel t1
        RIGHT JOIN tPairAP t2 ON (
                (t1.N1 = t2.N1 OR t1.N2 = t2.N1 OR t1.N3 = t2.N1 OR t1.N4 = t2.N1 OR t1.N5 = t2.N1 OR t1.N6 = t2.N1)
                AND (t1.N1 = t2.N2 OR t1.N2 = t2.N2 OR t1.N3 = t2.N2 OR t1.N4 = t2.N2 OR t1.N5 = t2.N2 OR t1.N6 = t2.N2)
            )
        WHERE t1.N1 IS NOT NULL
    )

    UPDATE tModel
    SET Flag= CASE WHEN Subquery.ID IS NOT NULL THEN 'Y' ELSE 'N' END
    FROM tModel
    LEFT JOIN Subquery ON tModel.ID = Subquery.ID;

由于表的大小,查询需要 20 小时 30 分钟才能运行。

由于长度,我认为在 python 上运行该检查会很快,因此,为了检查运行时间的差异,我想考虑两种方法。

我尝试的第一个途径是使用 Numpay。为此,我创建了 txt 文件,以便可以将其作为 Numpy 数组加载。 我将这两个文件命名为表,它们仅包含 tModel.txt 的 N1、N2、N3、N4、N5、N6 和 tPairAP.txt 的 N1、N2。

然后我也想过为 Numpy 编写两种不同的方式来处理这个任务

NUMPY 选项 1

import numpy as np

# Load the text file as numpy arrays
tModel = np.loadtxt('C:\\py\\SQL ON\\py_files\\tModel.txt', delimiter=','))
tPairAP = np.loadtxt('C:\\py\\SQL ON\\py_files\\tPairAP.txt', delimiter=','))


# Check if any arrays of Array1 contain all elements from any arrays of Array2
contains_elements = np.array([np.all(np.isin(tModel, arr)) for arr in tPairAP])

# Create a list of flags based on the contains_elements array
flags = np.where(contains_elements, 'Y', 'N')

# Write the list of lists of List1 and flags to a new file
with open('C:\\py\\SQL ON\\tModelNoPair.txt', 'w') as file:
    for i in range(len(tModel)):
        file.write(str(tModel[i]) + ' ' + flags[i] + '\n')

令我惊讶的是,我发现运行 python 代码需要很长时间,而且比 SQL 花费的时间还要长。我让上面的代码运行了 33 小时,但代码甚至还没有接近完成运行

NUMPY选项2

import numpy as np

# Convert List1 and List2 to numpy arrays
tModel = np.loadtxt('C:\\py\\SQL ON\\py_files\\tModel.txt', delimiter=','))
tPairAP = np.loadtxt('C:\\py\\SQL ON\\py_files\\tPairAP.txt', delimiter=','))

# Create a list to store the flags
flags = []

# Iterate over each list in List1
for l1 in tModel:
    flag = 'N'
    # Iterate over each list in List2
    for l2 in tPairAP:
        if np.isin(l1, l2).sum() == 2:
            flag = 'Y'
            break
    flags.append(flag)

# Write the results to a file
with open('C:\\py\\SQL ON\\tModelNoPair.txt', 'w') as file:
    for i, flag in enumerate(flags):
        file.write(f'{tModel[i]} {flag}\n')

我什至没有尝试运行第二个选项,因为我认为这更像是一个通用版本,我可以使用它,例如 tPairAP 不仅有 N1、N2,还有 N3、N4..Nn。然而,尽管我假设上面的代码有多快,但考虑到 NUMPY OPTION 1 的长度,我认为它不会比 SQL 查询运行得更快。

我想到的第三个选项是通过 python list 运行脚本。我编写了如下代码:

列表选项

import numpy as np
def check_elements(tModel, tPairAP):
    for sublist1 in tModel:
        for sublist2 in tPairAP:
            if all(elem in sublist1 for elem in sublist2):
                return 'Y'
    return 'N'

# lists
tModel = np.loadtxt('C:\\py\\SQL ON\\py_files\\tModel.txt', delimiter=',')
tPairAP = np.loadtxt('C:\\py\\SQL ON\\py_files\\tPairAP.txt', delimiter=',')

flags = []
for sublist1 in tModel:
    flag = check_elements(tModel, tPairAP)
    flags.append(flag)

with open('output.txt', 'w') as file:
for sublist, flag in zip(tModel, flags):
    file.write(str(sublist) + ' ' + flag + '\n')

现在,不用说,但在踢列表选项之前,我在互联网上做了一些研究,以了解列表是否比 numpy 更快,并且 numpay 似乎在数组中检查比列表更快。因此,我没有运行代码,因为我不希望它比 Numpy 更快。

所以我的问题是:numpy 怎么可能比 SQL 慢?据我所知,尽管不是 python 专家(我使用 numpy 来处理其他东西,比如非常大的方差协方差矩阵),numpy 应该更快,但看起来并非如此。

任何人都可以告诉我我的 python 代码是否写得不好,以及最终如何纠正它,使其比 SQL 更快,或者是否有更好的库来执行此任务,以及最终如何使用该库的示例?

谢谢

python sql arrays list numpy
1个回答
0
投票

算法:这可能会更快一点,因为它利用大表左连接到较小表的几个步骤。它假设每行的 tModel ID 都是唯一的。由于行数较多,可能值得分阶段运行(用 ; 分隔)。 旋转小表 tPairAP,使 N1 和 N2 垂直堆叠到 Ny 列中 - 将其另存为 tPairAPx。然后我们可以测试 tModel t1.N1 是否在 tPairAPx 列 Ny 中,并将其他 5 个(N2、N3、N4、N5、N6)作为(A1、A2、A3、A4、A5)与 Nx 一起返回。然后重复测试 tModel t1.N2 并将 (N1, N3, N4, N5, N6) 作为 (A1, A2, A3, A4, A5) 与 Nx 一起返回。对 N3、N4、N5 和 N6 重复这些测试。合并这些测试表并选择 Nx 不为空的位置以给出较小的表 - 步骤 1。

然后测试A1、A2、A3、A4、A5中的每一个是否都在tPairAPx列Ny中,并带回一个较小的表Step2,其中T2_ID不为空。然后 tModel 将 Step2 与 case when 语句左连接以给出结果。

create table tPairAPx
select t1.ID, "N1" as Nx, t1.N1 as Ny from tPairAP t1
union 
select t2.ID, "N2" as Nx, t2.N2 as Ny from tPairAP t2;

create table Step1
select Id, A1, A2, A3, A4, A5 from
(
      select t1.Id, t1.N2 as A1, t1.N3 as A2, t1.N4 as A3, t1.N5 as A4, t1.N6 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N1 = t2.Ny
union select t1.Id, t1.N1 as A1, t1.N3 as A2, t1.N4 as A3, t1.N5 as A4, t1.N6 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N2 = t2.Ny
union select t1.Id, t1.N1 as A1, t1.N2 as A2, t1.N4 as A3, t1.N5 as A4, t1.N6 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N3 = t2.Ny
union select t1.Id, t1.N1 as A1, t1.N2 as A2, t1.N3 as A3, t1.N5 as A4, t1.N6 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N4 = t2.Ny
union select t1.Id, t1.N1 as A1, t1.N2 as A2, t1.N3 as A3, t1.N4 as A4, t1.N6 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N5 = t2.Ny
union select t1.Id, t1.N1 as A1, t1.N2 as A2, t1.N3 as A3, t1.N4 as A4, t1.N5 as A5, t2.Nx
FROM tModel t1 LEFT JOIN tPairAPx t2 on t1.N6 = t2.Ny
)
where Nx is not null;

create table Step2
select t1.ID from (
select t1.Id, t2.ID as T2_ID from Step1 t1 LEFT JOIN tPairAPx t2 on t1.A1 = t2.Ny
union
select t1.Id, t2.ID as T2_ID from Step1 t1 LEFT JOIN tPairAPx t2 on t1.A2 = t2.Ny
union
select t1.Id, t2.ID as T2_ID from Step1 t1 LEFT JOIN tPairAPx t2 on t1.A3 = t2.Ny
union
select t1.Id, t2.ID as T2_ID from Step1 t1 LEFT JOIN tPairAPx t2 on t1.A4 = t2.Ny
union
select t1.Id, t2.ID as T2_ID from Step1 t1 LEFT JOIN tPairAPx t2 on t1.A5 = t2.Ny
)
where T2_ID is not null;

select t1.ID, t1.Date, t1.N1, t1.N2, t1.N3, t1.N4, t1.N5, t1.N6,
case when t1.ID in (select ID from Step2) then "Y"
else "N" end as Flag
from tModel t1 left join Step2 t2 on t1.ID = t2.ID
© www.soinside.com 2019 - 2024. All rights reserved.