过去两天我有一个问题让我疯了。我基本上有4个表继承按以下顺序:
users
|
categories blogs
| | |
---- pages visits
因此,用户拥有许多博客,其中包含许多页面和访问次数。每个页面也属于一个类别。
我想要的是提取具有以下关联计数的所有用户:
我的查询如下:
SELECT
u.id
u.username,
COUNT(b.id) as blogs_count,
COUNT(p.id) as pages_count,
COUNT(v.id) as visits_count,
COUNT(distinct ip_address) as visitors_count
COUNT(c.id) as categories_count
FROM
users u
LEFT JOIN
blogs b ON(b.user_id=u.id)
LEFT JOIN
pages p ON(p.blog_id=b.id)
LEFT JOIN
visits v ON(v.blog_id=b.id)
LEFT JOIN
categories c ON(v.category_id=c.id)
GROUP BY u.id, blogs_count, pages_count, visits_count,
visitors_count, categories_count
我应该让24个用户获得他们的计数但是,鉴于我有近300,000次访问,我得到了我的SQL数据库永远可能会挂起数百万行。 我不是数据库大师,这很明显。有人能指出我正确的方向,所以我可以做出一个好的查询,甚至可以在数百万条记录上表现良好(当然还有合适的硬件)?
答案 0 :(得分:0)
SELECT
u.id
u.username,
COUNT(b.id) as blogs_count,
COUNT(p.id) as pages_count,
COUNT(v.id) as visits_count,
COUNT(distinct ip_address) as visitors_count
COUNT(c.id) as categories_count
FROM
users u
LEFT JOIN
blogs b ON(b.user_id=u.id)
LEFT JOIN
pages p ON(p.blog_id=b.id)
LEFT JOIN
visits v ON(v.blog_id=b.id)
LEFT JOIN
categories c ON(v.category_id=c.id)
GROUP BY u.id
尝试按照规定从您的论坛中删除blogs_count,pages_count,visits_count,visitor_count,categories_count。
答案 1 :(得分:0)
试试这个:
SELECT u.id,
u.username,
COUNT(b.id) AS blogs_count,
COALESCE(MAX(p.pagecnt), 0) AS pages_count,
COALESCE(MAX(v.visitscnt), 0) AS visits_count,
COALESCE(MAX(v.visitorscnt), 0) AS visitors_count,
COALESCE(MAX(c.catcnt), 0) AS categories_count
FROM users u
LEFT JOIN blogs b ON u.id = b.user_id
LEFT JOIN (
SELECT blog_id,
COUNT(*) AS pagecnt
FROM pages
GROUP BY blog_id
) p ON b.id = p.blog_id
LEFT JOIN (
SELECT blog_id,
COUNT(*) AS visitscnt,
COUNT(DISTINCT ip_address) AS visitorscnt
FROM visits
GROUP BY blog_id
) v ON b.id = v.blog_id
LEFT JOIN (
SELECT aa.id,
COUNT(DISTINCT dd.id) AS catcnt
FROM users aa
JOIN blogs bb ON aa.id = bb.user_id
JOIN pages cc ON bb.id = cc.blog_id
JOIN categories dd ON cc.category_id = dd.id
GROUP BY aa.id
) c ON u.id = c.id
GROUP BY u.id,
u.username
这也适用于不同的DBMS,如PGSQL,SQL-Server等。
挑战在于你有这种1:M关系的层次结构,将它们连接在一起可以很容易地抛弃不同类型的计数(因为你想要在某些地方使用不同的计数,但在其他地方需要总计数)。
我决定做的是首先选择每个页面的计数并访问/区分访问者,按blog_id
进行分组。这确保了每个blog_id
只能获得一行,即使在加入博客表上的子选择后也是如此。
对于类别计数,您需要为每个 用户 计算不同的类别,但挑战是类别在关系层次结构中深入链接(到页面表) ),所以你必须创建一个单独的subselect加入user_id而不是blog_id。
即使该查询包含的子选择数量很多,它仍然应该非常快,因为没有两个子选择相互连接。只要在连接的任一侧有一个索引表(子选择实际上是未编入索引的临时表),您应该没问题。