代码之家  ›  专栏  ›  技术社区  ›  Simon

优化查询时需要帮助

  •  5
  • Simon  · 技术社区  · 15 年前

    incoming tours(id,name) 和 incoming_tours_cities(id_parrent, id_city)

    id 在第一个表中是唯一的,对于第一个表中的每一个唯一行,都有 id_city -在第二个表中(即。 id_parrent 身份证件 从第一张桌子)

    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")

    以及 second_tour 有城市列表- ("1","5")


    4 和 74 :

    现在,我需要从第一个表中获取所有行 二者都 值在城市列表中。i、 它必须只返回 第一次参观 (因为有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个)时,查询速度会减慢。

    i、 当我试着跑的时候

    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 (尽管我在表中设置了索引)

    多谢

    6 回复  |  直到 15 年前
        1
  •  6
  •   ksogor    15 年前
    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
    

    但你需要改变城市总数。

        2
  •  2
  •   Narf    15 年前
    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 您正在搜索,但是由于您动态生成查询,所以这不应该是问题。

        3
  •  1
  •   Aether    15 年前

    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)
    
        4
  •  0
  •   Luca Martini    15 年前

    只是个提示。 IN a中的运算符 WHERE 条款,你可以希望操作员的短路 AND 可能会消除不必要的 JOIN 在执行不遵守约束的巡更期间。

        5
  •  0
  •   pharalia    15 年前

    这是个奇怪的查询方式

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

    我 认为

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

        6
  •  0
  •   Catch22    15 年前

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