【问题标题】:How to make a COUNT with better performace?如何制作性能更好的 COUNT?
【发布时间】:2019-12-19 17:20:15
【问题描述】:

我正在使用这个查询,它需要 3 秒才能运行。表通告有 255k 行,表地址有 30k 行。

SELECT COUNT(DISTINCT ad.id) as total_address
FROM (
  SELECT
    ad.id, an.id as announce_id,
    an.buy_price as buy_price,
    an.rental_price as rental_price,
    (SELECT Count(*) FROM owner_address 
      WHERE address_id = ad.id) as totalOwnersAd,
    (SELECT Count(*) FROM owner_announce 
      WHERE announce_id = an.id) as totalOwnersAn
  FROM addresses ad
  RIGHT JOIN announces an ON ad.id = an.address_id
  WHERE an.name = 'tralala' and ad.name = 'tralala'
) ad

还有子查询:

SELECT
  ad.id, an.id as announce_id,
  an.buy_price as buy_price,
  an.rental_price as rental_price,
  (SELECT Count(*) FROM owner_address 
    WHERE address_id = ad.id) as totalOwnersAd,
  (SELECT Count(*) FROM owner_announce 
    WHERE announce_id = an.id) as totalOwnersAn
FROM addresses ad
RIGHT JOIN announces an ON ad.id = an.address_id
WHERE an.name = 'tralala' and ad.name = 'tralala'

运行需要 17 毫秒。

为什么我的COUNT花了这么长时间?

我正在使用 MySql。

由于我的动态过滤器,我需要加入 announcesaddresses 表。例如,当我需要计算具有公告列 X 等于 Y 的地址时。

编辑:

我试过了:

SELECT COUNT(DISTINCT ad.address_id) as total_address
        FROM announces an JOIN ( 
           SELECT adds.id as address_id
                FROM (
                      SELECT id,
                      (SELECT Count(*) FROM owner_address WHERE address_id = ad.id) as totalOwnersAd
                      from addresses ad


             )  as adds
        ) as ad ON ad.address_id = an.address_id
        WHERE 
         ( an.bedroom = 2 ) 

它的速度提高了 10%,但仍然需要很长时间。当我有地址过滤器时它会更快。

到底有没有索引子查询表?

【问题讨论】:

  • 可能是因为您在返回 first 行而不是返回 last 行时计算 17 毫秒。您的第一个子查询需要处理所有数据。
  • 你为什么有那个外部查询?您可以在内部查询中删除SELECT 之后的所有列和表达式,然后在其中添加count()。优化器可能无论如何都会这样做,因此它可能不会影响性能,但会影响可读性。
  • @stickybit 我编辑我的问题以更好地解释它。
  • 如果我创建一个临时表和索引id,这会是一个解决方案吗?
  • 你的表有索引吗?怎么样?

标签: mysql sql query-optimization sql-optimization


【解决方案1】:

我只是好奇你为什么不使用:

select count(distinct an.address_id)
from announces;

这似乎是一种更简单的方法来得出相同的值。

编辑:

对于您修改后的查询,这更简单:

SELECT COUNT(DISTINCT an.address_id)
FROM addresses ad JOIN
     announces an
     ON ad.id = an.address_id
WHERE an.name = 'tralala' and ad.name = 'tralala';

right join 是不必要的,因为WHERE 条件会将其转换为inner join。子查询和附加列不是必需的。

【讨论】:

  • 我无法使用,因为我的查询需要动态的位置和需求
  • @TiagoCastro - 如我所见 - 此查询将返回与您的第一个查询完全相同的结果。
  • 我不能这样做,因为我的动态过滤器需要正确加入才能宣布。例如,当我需要计算我的announce_name 等于'the'的地址时。
  • @TiagoCastro 您也可以将 WHERE 条件附加到此查询中。
  • @PaulSpiegel 问题是我的 WHERE 条件同时需要两个表(公告和地址)。例如:WHERE address.name = 'lala' AND Advertisements.name = 'lalala'
【解决方案2】:

好的,经过深思熟虑,我减少了 15 倍,它并不完美,但现在还可以。

我的查询:

 SELECT COUNT(DISTINCT ad.address_id) as total_address
        FROM (
           SELECT ann.id as announce_id, ann.buy_price as buy_price, ann.address_id as address_id,
            ann.rental_price as rental_price

            FROM (
                SELECT id, buy_price, rental_price, address_id,
                  (SELECT Count(*) FROM owner_announce 
  WHERE announce_id = an.id) as totalOwnersAn
              FROM announces an
              WHERE 
               ( an.parking_slots = 2 ) AND ( an.bedroom = 2 ) 
    ) as ann
) as anner
 JOIN ( 
           SELECT adds.id as address_id
                FROM (
                      SELECT id,
                      (SELECT Count(*) FROM owner_address WHERE address_id = ad.id) as totalOwnersAd
                      from addresses ad
                      WHERE 
                      city LIKE '%Campinas%'
             )  as adds
        ) as ad ON ad.address_id = anner.address_id

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-23
    • 2011-02-12
    • 2016-05-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-26
    相关资源
    最近更新 更多