需要帮助优化查询

发布于 2024-09-28 20:30:37 字数 1820 浏览 11 评论 0原文

我有两个表 - 第一个表中的 incomingtours(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")


让我们假设我有两个值 - 474

现在,我需要从第一个表中获取所有行,其中我的两个值都在城市列表中。即它必须只返回 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 内运行查询时(尽管我在表中设置了索引)

我能做什么来优化它?

非常感谢

I have two tables - incoming tours(id,name) and incoming_tours_cities(id_parrent, id_city)

id in first table is unique, and for each unique row from first table there is the list of id_city - s in second table(i.e. id_parrent in second table is equal to id from first table)

For example

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-----|
........................

That means that first_tour has list of cities - ("4","5","27","74")

AND second_tour has list of cities - ("1","5")


Let's assume i have two values - 4 and 74:

Now, i need to get all rows from first table, where my both values are in the list of cities. i.e it must return only the first_tour (because 4 and 74 are in it's list of cities)

So, i wrote the following query

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'

And that works fine.

But i generate the query dynamically, and when the count of joins is big (about 15) the query slowing down.

i.e. when i try to run

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'

the query run's in 45s(despite on i set indexes in the tables)

What can i do, to optimaze it?

Thanks much

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

平定天下 2024-10-05 20:30:37
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

但您需要更改城市总数。

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

But you need to change number of total cities count.

尛丟丟 2024-10-05 20:30:37
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 计数,但由于您是动态生成查询,因此这应该不是问题。

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;

You will have to change c=2 to whatever the count of id_city you are searching is, but since you generate the query dynamically, that shouldn't be a problem.

淡墨 2024-10-05 20:30:37

我很确定这可行,但不太确定它是否是最佳的。

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)

I'm pretty sure this works, but a lot less sure that it is optimal.

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)
记忆消瘦 2024-10-05 20:30:37

只是一个提示。
如果您在 WHERE 子句中使用 IN 运算符,则可以希望运算符 AND 的短路可以删除不必要的 JOIN在不遵守约束的游览执行期间。

Just an hint.
If you use the IN operator in a WHERE clause, you can hope that the short-circuit of operator AND may remove unnecessary JOINs during the execution for the tours that do not respect the constraint.

属性 2024-10-05 20:30:37

执行该查询的方式似乎很奇怪,这里

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'));

认为可以做到这一点,但未经测试...

编辑:向子查询添加表别名

Seems like an odd way to do that query, here

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'));

I think that does it, but not tested...

EDIT: Added table alias to sub-query

彩扇题诗 2024-10-05 20:30:37

我使用 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

I've written this query using CTE's and it includes the test data in the query. You'll need to modify it so that it queries the real tables instead. Not sure how it performs on a large dataset...

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文