我有两张桌子 - incoming tours(id,name)
和incoming_tours_cities(id_parrent, id_city)
id
是唯一的,对于第一个表中的每个唯一行,第二个表中的id_city
- s列表(即第二个表中的id_parrent
等于来自第一张表的id
例如
incoming_tours
|--id--|------name-----|
|---1--|---first_tour--|
|---2--|--second_tour--|
|---3--|--thirth_tour--|
|---4--|--hourth_tour--|
incoming_tours_cities
|-id_parrent-|-id_city-|
|------1-----|---4-----|
|------1-----|---5-----|
|------1-----|---27----|
|------1-----|---74----|
|------2-----|---1-----|
|------2-----|---5-----|
........................
这意味着first_tour
包含城市列表 - ("4","5","27","74")
AND second_tour
包含城市列表 - ("1","5")
我们假设我有两个值 - 4
和74
:
现在,我需要从第一个表中获取所有行,其中两个值都在城市列表中。即它必须只返回 first_tour (因为4和74位于其城市列表中)
所以,我写了以下查询
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
这很好用。
但是我动态生成查询,当连接数很大(大约15)时,查询速度变慢。
即。当我试图运行时
SELECT t.name
FROM `incoming_tours` t
JOIN `incoming_tours_cities` tc0 ON tc0.id_parrent = t.id
AND tc0.id_city = '4'
JOIN `incoming_tours_cities` tc1 ON tc1.id_parrent = t.id
AND tc1.id_city = '74'
.........................................................
JOIN `incoming_tours_cities` tc15 ON tc15.id_parrent = t.id
AND tc15.id_city = 'some_value'
45s
中的查询运行(尽管我在表中设置了索引)
我能做些什么来优化它?
非常感谢
答案 0 :(得分:6)
SELECT t.name
FROM incoming_tours t INNER JOIN
( SELECT id_parrent
FROM incoming_tours_cities
WHERE id IN (4, 74)
GROUP BY id_parrent
HAVING count(id_city) = 2) resultset
ON resultset.id_parrent = t.id
但您需要更改总城市数量。
答案 1 :(得分:2)
SELECT name
FROM (
SELECT DISTINCT(incoming_tours.name) AS name,
COUNT(incoming_tours_cities.id_city) AS c
FROM incoming_tours
JOIN incoming_tours_cities
ON incoming_tours.id=incoming_tours_cities.id_parrent
WHERE incoming_tours_cities.id_city IN(4,74)
HAVING c=2
) t1;
您必须将c=2
更改为您正在搜索的id_city
计数,但由于您动态生成查询,这应该不是问题。
答案 2 :(得分:1)
我很确定这是有效的,但不太确定它是最佳的。
SELECT * FROM incoming_tours
WHERE
id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=4)
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=74)
...
AND id IN (SELECT id_parrent FROM incoming_tours_cities WHERE id_city=some_value)
答案 3 :(得分:0)
只是一个暗示。
如果您在IN
子句中使用WHERE
运算符,则可以希望运算符AND
的短路可以在执行期间删除不必要的JOIN
不尊重约束。
答案 4 :(得分:0)
这似乎是一种奇怪的方式来进行查询,这里
SELECT t.name FROM `incoming_tours` as t WHERE t.id IN (SELECT id_parrent FROM `incoming_tours_cities` as tc WHERE tc.id_city IN ('4','74'));
我认为这样做,但未经过测试......
编辑:为子查询添加了表别名
答案 5 :(得分:0)
我使用CTE编写了这个查询,它在查询中包含了测试数据。您需要对其进行修改,以便它查询真实的表格。不确定它在大型数据集上的表现......
Declare @numCities int = 2
;with incoming_tours(id, name) AS
(
select 1, 'first_tour' union all
select 2, 'second_tour' union all
select 3, 'third_tour' union all
select 4, 'fourth_tour'
)
, incoming_tours_cities(id_parent, id_city) AS
(
select 1, 4 union all
select 1, 5 union all
select 1, 27 union all
select 1, 74 union all
select 2, 1 union all
select 2, 5
)
, cityIds(id_city) AS
(
select 4
union all select 5
/* Add all city ids you need to check in this table */
)
, common_cities(id_city, tour_id, tour_name) AS
(
select c.id_city, it.id, it.name
from cityIds C, Incoming_tours_cities tc, incoming_tours it
where C.id_city = tc.id_city
and tc.id_parent = it.id
)
, tours_with_all_cities(id_city) As
(
select tour_id from common_cities
group by tour_id
having COUNT(id_city) = @numCities
)
select it.name from incoming_tours it, tours_with_all_cities tic
where it.id = tic.id_city