我有一个像这样的字段表:
product_id |aid |value|
------------|-------|-----|
789 |6 |1 |
789 |6 |3 | -->aid = 6 , value = 3
789 | 8| 8| -->rows that i want with aid 8
789 | 8| 11| -->rows that i want with aid 8
789 | 8| 82| -->rows that i want with aid 8
------------|-------|-----|
790 |6 |2 |
790 |6 |3 | -->aid = 6 , value = 3
790 |6 |4 |
790 | 8| 8| -->rows that i want with aid 8
790 | 8| 16| -->rows that i want with aid 8
------------|-------|-----|
791 |6 |7 |
791 |8 |13 |
------------|-------|-----|
对于具有一对(援助= 6 AND值= 3)的特定产品,我希望所有行的辅助= 8
我做了什么:
首先,我选择具有aid = 6
和value = 3
的不同product_ids
然后我选择所有行,其中product_ids是IN先前的选择查询。
这是我的查询,大约需要1秒钟。
SELECT DISTINCT `value` FROM `fields`
WHERE aid = 8 AND product_id IN
(
SELECT DISTINCT `fields`.product_id FROM `fields`
WHERE aid = 6 AND `value` = 3
)
值结果为8,11,82,16
有更优化的方法吗?
答案 0 :(得分:1)
首先,子查询中的distinct
应该是不必要的。我不确定MySQL是否会优化它。所以,从:
SELECT DISTINCT f.`value`
FROM `fields` f
WHERE f.aid = 8 AND
f.product_id IN (SELECT f2.product_id
FROM `fields` f2
WHERE f2.aid = 6 AND f2.`value` = 3
);
对于此查询,您需要fields(aid, value, product_id)
上的索引。
在早期版本的MySQL中,最好用IN
替换EXISTS
子查询。如果您的查询现在在一秒钟内完成,那么您可能处于更新版本。
答案 1 :(得分:0)
Gordon向您展示了IN
方法,如果您最终需要调整性能,那么您可能还需要考虑EXISTS
和/或JOIN
方法3所有方法都有不同的优缺点,具体取决于您的数据大小和复杂性。
EXISTS
只使用相关的子查询
SELECT f.*
FROM
`fields` f
WHERE
f.aid = 8
EXISTS (
SELECT 1
FROM `fields` f2
WHERE
f2.aid = 6
AND f2.`value` = 3
AND f1.product_id = f2.product_id)
对于在这种情况下保持不同的连接方法,因为如果6& 3可以代表不止一次。
SELECT f.*
FROM
`fields` f
INNER JOIN (
SELECT DISTINCT `fields`.product_id FROM `fields`
WHERE aid = 6 AND `value` = 3
) t
ON f.product_id = t.product_i
WHERE
f.aid = 8
答案 2 :(得分:0)
首先,如果您还没有索引,请将以下索引添加到您的表格中。
ALTER TABLE fields ADD KEY (aid, product_id, value);
顺便说一句,在询问SQL问题时,如果你发布SHOW CREATE TABLE
的输出会有帮助,这样我们就可以看到你是否已经定义了任何索引或约束。
sql> SHOW CREATE TABLE fields\G
Table: fields
Create Table: CREATE TABLE `fields` (
`product_id` int(11) DEFAULT NULL,
`aid` int(11) DEFAULT NULL,
`value` int(11) DEFAULT NULL,
KEY `aid` (`aid`,`product_id`,`value`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
接下来,尝试此查询:
SELECT DISTINCT f1.value
FROM fields AS f1
INNER JOIN fields AS f2
ON f1.product_id=f2.product_id
WHERE f1.aid=8 AND f2.aid=6 AND f2.value=3;
这不使用子查询,只使用索引查找。我们并不关心减少f2中匹配行的集合,因为无论如何都会由DISTINCT处理。
输出(在MySQL 8.0.0-dmr上测试):
+-------+
| value |
+-------+
| 8 |
| 11 |
| 82 |
| 16 |
+-------+
这里是EXPLAIN报告以显示优化:
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: f2
partitions: NULL
type: ref
possible_keys: aid
key: aid
key_len: 5
ref: const
rows: 6
filtered: 10.00
Extra: Using where; Using index; Using temporary
*************************** 2. row ***************************
id: 1
select_type: SIMPLE
table: f1
partitions: NULL
type: ref
possible_keys: aid
key: aid
key_len: 10
ref: const,test.f2.product_id
rows: 2
filtered: 100.00
Extra: Using index
两个表都获得"使用索引"优化,因此他们使用覆盖索引。
两个表都使用索引查找来缩小已检查行的数量。
还有一个临时表会导致一些开销。但由于DISTINCT,这是不可避免的。但至少它只是一个临时表,而不是由于在子查询中使用DISTINCT而导致的多个临时表。临时表应该很小,因为它只需要存储已匹配的行。