如何在 MySQL 中更好地使用 Pivot Table 上的逻辑门

How to better use Logic Gates on Pivot Table in MySQL

目标是使用基于数据透视表的逻辑查询数据 table。我想支持 6 个逻辑门,[AND, OR, XOR, NAND, NOR, XNOR],这样当用户创建自定义过滤器时,他们可以提供逻辑门和要在逻辑中使用的 tags.id 值。

示例数据:

+----------+
| data     |
|----+-----+
| id | ... |
+----+-----+
| s  | ... |
| t  | ... |
| u  | ... |
| v  | ... |
| w  | ... |
| x  | ... |
| y  | ... |
| z  | ... |
+----+-----+

+---------+
| pivot   |
|----+----|
| c1 | c2 |
+----+----+
| t  | a  |
| t  | b  |
| t  | c  |
| u  | a  |
| u  | b  |
| v  | b  |
| v  | c  |
| w  | a  |
| w  | c  |
| x  | a  |
| y  | b  |
| z  | c  |
+----+----+

+----------+
| tags     |
+----+-----+
| id | ... |
+----+-----+
| a  | ... |
| b  | ... |
| c  | ... |
| d  | ... |
+----+-----+

预期产出:

查询表示:

数据目前约为 30K 行,标签约为 1.5K 行。我目前正在使用 100K 行填充此数据透视表 table 以对上述查询进行一些测试。我觉得多个 IN() 语句会使速度变慢。

是否可以使用视图、联接或其他 MySQL 操作对这些查询进行微调?

此外,如果您有更好的结构建议,我会洗耳恭听。我以前曾尝试在数据中使用 JSON 字段来避免使用枢轴 table,但结果非常慢。

EDIT:虽然 OR(...)NOR(...) 查询工作得很好(~80ms),但 AND(...) 查询表现不佳(~ 1300 毫秒)。查看 EXPLAIN 并尝试遵循 MySQL subquery opimization suggestions 使用 DISTINCT ... INNER JOIN 生成更好的单个子查询实际上使事情变得更糟。

我通过测试偶然发现的是,与在纯 MySQL.[=49= 中相比,我可以在 Node 中使用 lodash 的 _.intersection(...) 更快地对多个 id 列表进行交集]

因此,我可以从 MySQL 中提取单独的子查询,然后在 API 本身中使用 lodash 来执行,而不是使用子查询来形成 AND(...) 逻辑交集,然后生成一个列表以在最后的 IN(...) 语句中使用以进行最终过滤。

OR(a, b, c) = [t, u, v, w, x, y, z]

SELECT GROUP_CONCAT(DISTINCT c1)
    FROM pivot
    WHERE p2 IN ('a', 'b', 'c');

其余的比较乱,所以让我问一下可以存在多少个不同的c1和c2。如果不超过 64,可以对 BIGINT UNSIGNED.

中的位进行布尔运算

另请参阅数据类型 ENUMSET

如果您有 MySQL 8.0,布尔运算符适用于 BLOB,从而远远超过 64。

VIEWs是语法糖,不是性能工具。

IN(SELECT ...) 通常效率很低;尝试使用 EXISTS( SELECT 1 ... )JOIN(或 LEFT JOIN)来避免它。

AND(a, b, c) = [t]

可以这样实现:

SELECT GROUP_CONCAT(DISTINCT c1)
    FROM (
        SELECT c1
            FROM pivot
            WHERE c2 IN ('a', 'b', 'c')
            GROUP BY c1
            HAVING COUNT(*) = 3   -- the number of items in a,b,c
         ) AS x ;

注:

c2 IN ('a', 'b', 'c')

可以这样写:

FIND_IN_SET(c2, 'a,b,c')

这可能更容易将您的运算符转换为存储例程。