【问题标题】:Filter rows with several large vectors过滤具有多个大向量的行
【发布时间】:2016-06-20 15:01:34
【问题描述】:

我有一个包含几列的表 A:

 A              B              C
 1              2              7  
 1              2              8 
 2              2              1 
 1              3              1 

我必须在 Java 中构建一个函数,它接受 3 个向量作为输入,vA、vB、vC,并返回具有向量中任何值的行。数组用作过滤器。 A = {1,2,3,4}, b = {2}, C={7} 将返回一行,但 A = {1}, b = {2}, C={0} 不会,因为 c 列中没有行的值为 0

  • 向量太大了,不可能像WHERE (c = ? OR c = ? ...c = ? )那样生成很多OR
  • 必须避免 SQL 注入
  • 性能至关重要

其他线程(https://stackoverflow.com/a/1532454/1991779),建议一个临时表,然后加入这些表。问题是我有几个向量来匹配几列而不是一个。我想我可以创建一个表,插入所有值,然后使用

 WHERE A IN (SELECT A FROM TEMP ) AND B IN (SELECT B FROM TEMP ) AND  C
 IN (SELECT C FROM TEMP )

但是,我认为使用JOIN 而不是IN 会快得多。任何建议使用Join 而不是IN

有什么建议吗?

【问题讨论】:

  • 哪里可能存在,因为引擎在第一次出现时会停止查找。
  • In 只是创建一堆 OR 语句的简写(可能会带来小的性能提升,但我还没有经历过)。如果要使用连接,可以将要匹配的值转储到临时表中,然后将表连接到相关字段上的该临时表。
  • 我应该如何在 tmp 表中插入值?每行不能有一个值,对吗?唯一的方法是做所有的排列,否则,连接会错过一些有效的情况吗?对吗

标签: java mysql


【解决方案1】:

这使用了cross join 又名笛卡尔积(所有排列)的概念。因此,您的数组会生成一个行数为x*y*z 的派生表(在内存中),其中 x、y、z 是数组的大小。如果您提供大小为 3,4 和 5 的数组,则派生表的行数将为 3*4*5=60。

您提供的产生一行的数组匹配只有 4*1*1=4

thing7 下面是您正在搜索的主表。即使有大量数据,covering index 也应该让这个东西飞起来。覆盖索引是一种通过索引的 b-tree 扫描提供信息的索引,并且不需要读取数据页。为什么?因为需要的数据在索引中。在你的情况下,非常薄。

表 A B C 用作您的数组。

唯一要说的是每个派生表都需要一个名称。所以我们在查询中将其命名为xDerived。将派生表视为在内存中返回和使用的东西。它不是物理表。

架构

create table thing7
(   id int auto_increment primary key,
    A int not null,
    B int not null,
    C int not null,
    index(A,B,C) -- covering index (uber-thin, uber-fast)
);

insert thing7(A,B,C) values
(1,2,7),  
(1,2,8), 
(2,2,1), 
(1,3,1);

create table A
(   id int auto_increment primary key,
    value int
);
create table B
(   id int auto_increment primary key,
    value int
);
create table C
(   id int auto_increment primary key,
    value int
);

测试 1

truncate table A;
truncate table B;
truncate table C;
insert A (value) values (1),(2),(3),(4);
insert B (value) values (2);
insert C (value) values (7);

select t7.* 
from thing7 t7  
join 
(   select A.value as Avalue, B.value as Bvalue, C.value as Cvalue 
    from A 
    cross join B 
    cross join C 
    order by a.value,b.value,c.value 
) xDerived 
on xDerived.Avalue=t7.A and xDerived.Bvalue=t7.B and xDerived.Cvalue=t7.C; 
+----+---+---+---+
| id | A | B | C |
+----+---+---+---+
|  1 | 1 | 2 | 7 |
+----+---+---+---+

..

测试 2

truncate table A;
truncate table B;
truncate table C;
insert A (value) values (1);
insert B (value) values (2);
insert C (value) values (0);

select t7.*
from thing7 t7 
join
(   select A.value as Avalue, B.value as Bvalue, C.value as Cvalue
    from A
    cross join B
    cross join C
    order by a.value,b.value,c.value
) xDerived
on xDerived.Avalue=t7.A and xDerived.Bvalue=t7.B and xDerived.Cvalue=t7.C;
-- no rows returned

将其转换为基于会话的搜索将非常容易。有一个概念,其中要搜索的数组(表 A B C)有一个会话列。然后它将促进多用户并发使用。但这是过度设计的答案,但请询问您是否需要更多信息。

【讨论】:

  • 要使其基于会话,请在创建表时执行“创建临时表”。排序是否会影响性能?
  • 对我来说,如果性能是关键,则不应将临时表用于这些类型的事情。这是由于 DDL 命令的开销造成的。这很容易测试。例如,我注意到有一次我在堆栈上展示了使用临时表与不使用临时表的调用有显着改进。如果不是,它将使用普通的非临时表并利用会话概念。你的会话/我的会话。它建立会话的方式是通过从控制表中检索的 auto_inc 值。因此,我们每个人都彼此安全地分割(高并发系统)
  • 但是测试将把它带入日光之中,哪些适合您,需要哪些性能。至于您关于订购是否有影响的问题,我看不出有什么不同,因为thing7 表已经具有covering index 的最佳设置,而目前您的 A B C 是如此之小以至于索引' 从来没有在小表上使用过(即使你有这些索引)。他们只是被跳过。我可以为您指出一个手册页,该页面明确回答了为什么它们被跳过。
  • 您能否评估一下我如何使用非临时表并仍然执行基于会话的搜索。
  • 评估是什么意思?我只是在上面提到了如何做到这一点。我认为您应该做的是实现此代码并评估您的喜好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-20
  • 1970-01-01
相关资源
最近更新 更多