Mysql 如何使用数据列表在_集中查找_

Mysql 如何使用数据列表在_集中查找_,mysql,Mysql,我以前多次使用过FIND_IN_SET,但这种情况有点不同 早些时候,我在表中搜索一个值,如 SELECT * FROM tbl_name where find_in_set('1212121212', sku) 但现在我有了要在表中搜索的SKU列表。例如 '3698520147','088586004490','868332000057','081308003405','088394000028','089541300893','0732511000148','009191711092','

我以前多次使用过
FIND_IN_SET
,但这种情况有点不同

早些时候,我在表中搜索一个值,如

SELECT * FROM tbl_name where find_in_set('1212121212', sku)
但现在我有了要在表中搜索的SKU列表。例如

'3698520147','088586004490','868332000057','081308003405','088394000028','089541300893','0732511000148','009191711092','752830528161'
我在表
SKU
中有两列,如081308003405和
SKU变体
在SKU列中,我保存单个值,但在变体列中,我以逗号分隔格式保存值,如
081308003405088394000028089541300893

SELECT * FROM tbl_name 
WHERE 1 
AND upc IN ('3698520147','088586004490','868332000057','081308003405','088394000028',
'089541300893','0732511000148','009191711092','752830528161')
我正在使用IN函数搜索UPC值,现在我想在variation列中搜索variation。这是我关心的问题,是如何使用“变体”列中的SKU列表进行搜索

现在,我必须在循环中检查UPC的变化,这花费了太多的时间。下面是查询

SELECT id FROM products 
WHERE 1 AND upcVariation AND FIND_IN_SET('88076164444',upc_variation) > 0

您可以尝试以下示例:

SELECT * FROM TABLENAME 
WHERE 1 AND ( FIND_IN_SET('3698520147', SKU) 
        OR UPC IN ('3698520147') )

我有一个解决方案,你可以考虑这个解决方案:

1:在此处创建临时表示例:


2:使用临时表进行筛选。在数据集

中查找数据,首先考虑以规范的方式存储数据。这是一本好书:

现在-假设以下架构和数据:

create table products (
  id int auto_increment,
  upc varchar(50),
  upc_variation text,
  primary key (id),
  index (upc)
);
insert into products (upc, upc_variation) values
  ('01234', '01234,12345,23456'),
  ('56789', '45678,34567'),
  ('056789', '045678,034567');
我们希望找到具有变体的产品
'12345'
'34567'
。预期结果是第1行和第2行

规范化模式-多对多关系 不要将这些值存储在逗号分隔的列表中,而是创建一个新表,该表将产品ID与变体进行映射:

create table products_upc_variations (
  product_id int,
  upc_variation varchar(50),
  primary key (product_id, upc_variation),
  index  (upc_variation, product_id)
);
insert into products_upc_variations (product_id, upc_variation) values 
  (1, '01234'),
  (1, '12345'),
  (1, '23456'),
  (2, '45678'),
  (2, '34567'),
  (3, '045678'),
  (3, '034567');
select查询将是:

select distinct p.*
from products p
join products_upc_variations v on v.product_id = p.id
where v.upc_variation in ('12345', '34567');
如您所见,使用规范化的模式,问题可以通过一个非常基本的查询来解决。我们可以有效地使用指数

“利用”全文索引 通过
(upc\U变体)
上的全文索引,您可以使用:

select p.*
from products p
where match (upc_variation) against ('12345 34567');
这看起来相当“漂亮”,可能是有效的。但是,尽管它在这个例子中有效,我对这个解决方案感到不舒服,因为我不能确切地说它什么时候不起作用

使用JSON_OVERLAPS() 由于MySQL 8.0.17,您可以使用。您应该将值存储为JSON数组,或者“动态”将列表转换为JSON:

没有索引可用于此操作。但for
都无法在_SET()中找到

使用JSON_TABLE() 由于MySQL 8.0.4,您可以使用它“动态”生成数据的规范化表示。在这里,您可以将数据存储在JSON数组中,或者在查询中将列表转换为JSON:

select distinct p.*
from products p
join json_table(
  concat('["', replace(p.upc_variation, ',', '","'), '"]'),
  '$[*]' columns (upcv text path '$')
) v
where v.upcv in ('12345', '34567');
这里不能使用索引。这可能是这个答案中给出的最慢的解决方案

RLIKE/REGEXP 您还可以使用:


请参阅性能注意事项。影响性能的主要因素是是否可以使用某些索引。表达式的复杂性对整体性能的影响很小

步骤1是了解哪些可以优化,以及以何种方式优化:

Equal:        WHERE x = 1  -- can use index
IN/1:         WHERE x IN (1) -- Turned into the Equal case by Optimizer
IN/many:      WHERE x IN (22,33,44)  -- Usually worse than Equal and better than "range"
Easy OR:      WHERE (x = 22 OR x = 33) -- Turned into IN if possible
General OR:   WHERE (sku = 22 OR upc = 33) -- not sargable (cf UNION)
Easy LIKE:    WHERE x LIKE 'abc' -- turned into Equal
Range LIKE:   WHERE x LIKE 'abc%' -- equivalent to "range" test
Wild LIKE:    WHERE x LIKE '%abc%' -- not sargable
REGEXP:       WHERE x RLIKE 'aaa|bbb|ccc' -- not sargable
FIND_IN_SET:  WHERE FIND_IN_SET(x, '22,33,44')  -- not sargable, even for single item
JSON:         -- not sargable
FULLTEXT:     WHERE MATCH(x) AGAINST('aaa bbb ccc')  -- fast, but not equivalent
NOT:          WHERE NOT ((any of the above)) -- usually poor performance
“Sargable”--能够使用索引。措辞不同的“在函数调用中隐藏列”会阻止使用索引

全文:有很多限制:“面向单词”、最小单词大小、停止单词等,但应用时速度非常快。注意:当与外部测试一起使用时,
MATCH
首先出现(如果可能的话),然后将在不使用索引的情况下进行进一步筛选,但只对较小的行集进行筛选

即使表达式“可以”使用索引,它也“可能不会”。
WHERE
子句是否充分利用索引的讨论比这里要长得多

步骤2了解在进行多个测试时如何构建复合索引(
其中…和…
):

构造复合(多列)索引时,按以下顺序包括列:

  • “Equal”-此类列的任意数量
  • “IN/many”列
  • 一个范围测试(
    介于
    ='2020-02-20'
    和x<'2020-02-20'+间隔1天
    
    阅读

    建筑索引:
    萨尔盖博:

    多对多提示:

    好吧,我找到了一种在一个查询中完成这项工作的方法。我使用
    子句在一个查询中检查所有数据,它比在循环中工作得更快。在SQL FIDLE中添加您的表,并在回答中发布您的解决方案,这将对其他人有帮助。
    sku
    是一个值吗?还是一个通配符?如果可能是列表,请将列名设为复数(例如,
    sku
    sku\u列表
    )。否则,请翻转第一个示例中的参数。我已经完成了我在下面问题中提到的解决方案。顺便说一句,感谢您的回答语法是有效的,但性能很差-在您的示例中没有索引可能有用-它涉及两个不同的列。因此,它将涉及完整的表扫描。如何使用临时表,即不是存储过程吗?只需使用SQL查询创建一个内存表即可。创建临时表新建\u tbl选择*源\u tbl限制0;
    select distinct p.*
    from products p
    join json_table(
      concat('["', replace(p.upc_variation, ',', '","'), '"]'),
      '$[*]' columns (upcv text path '$')
    ) v
    where v.upcv in ('12345', '34567');
    
    select p.*
    from products p
    where p.upc_variation rlike '(^|,)(12345|34567)(,|$)'
    
    Equal:        WHERE x = 1  -- can use index
    IN/1:         WHERE x IN (1) -- Turned into the Equal case by Optimizer
    IN/many:      WHERE x IN (22,33,44)  -- Usually worse than Equal and better than "range"
    Easy OR:      WHERE (x = 22 OR x = 33) -- Turned into IN if possible
    General OR:   WHERE (sku = 22 OR upc = 33) -- not sargable (cf UNION)
    Easy LIKE:    WHERE x LIKE 'abc' -- turned into Equal
    Range LIKE:   WHERE x LIKE 'abc%' -- equivalent to "range" test
    Wild LIKE:    WHERE x LIKE '%abc%' -- not sargable
    REGEXP:       WHERE x RLIKE 'aaa|bbb|ccc' -- not sargable
    FIND_IN_SET:  WHERE FIND_IN_SET(x, '22,33,44')  -- not sargable, even for single item
    JSON:         -- not sargable
    FULLTEXT:     WHERE MATCH(x) AGAINST('aaa bbb ccc')  -- fast, but not equivalent
    NOT:          WHERE NOT ((any of the above)) -- usually poor performance
    
        AND x >= '2020-02-20'
        AND x  < '2020-02-20' + INTERVAL 1 DAY
    
    SELECT * FROM tbl_name t1,(select 
    
    group_concat('3698520147',',','088586004490',',','868332000057',',',
    '081308003405',',','088394000028',',','089541300893',',','0732511000148',',','009191711092',
    
    ',','752830528161') as skuid)t
    
    WHERE FIND_IN_SET(t1.sku,t.skuid)>0