我有一个页面,其中有一个<select>
菜单,其中包含一个小表(229行)中的所有值,例如<option value='KEY'>VALUE</option>
。
此选择菜单是在大型表(3.5M行)上运行的查询的过滤器。 在大表中是一个从小表引用KEY的外键。
但是,在大表查询的结果中,我还需要显示小表中的相对VALUE
。
我可以很容易地执行INNER JOIN
来检索结果,或者我可以对我的小表执行单独的“预先”查询,将其值获取到数组中,然后让应用程序获取{来自小表结果的{1}}。
该应用程序是用PHP编写的。
硬件资源是一个问题(现在无法升级到更高的实例,老板受限) - 我在Amazon Web Services实例上的t2.micro RDS上运行它。 我在WHERE&amp;中的列上添加了单个索引和覆盖索引。 HAVING子句,我的服务器报告我有46mb RAM可用。
鉴于上述情况,我知道VALUE
可能很昂贵,特别是在大桌子上。在这里做2个查询是否有意义,让应用程序处理一些工作,直到我可以协商更好的资源?
编辑:
没有加入:6.9秒
JOIN
加入:59.03秒
SELECT nationality_id, COUNT(DISTINCT(txn_id)) as numtrans,
SUM(sales) as sales, SUM(units) as units, YrQtr
FROM 1_txns
GROUP BY nationality_id;
EXPLAIN
'1', 'SIMPLE', '1_txns', 'index', 'covering,nat', 'nat', '5', NULL, '3141206', NULL
架构是
SELECT 4_nationality.nationality, COUNT(DISTINCT(txn_id)) as numtrans,
SUM(sales) as sales, SUM(units) as units, YrQtr
FROM 1_txns INNER JOIN 4_nationality USING (nationality_id)
GROUP BY nationality_id
HAVING YrQtr LIKE :period;
EXPLAIN
'1', 'SIMPLE', '4_nationality', 'ALL', 'PRIMARY', NULL, NULL, NULL, '229', 'Using temporary; Using filesort'
'1', 'SIMPLE', '1_txns', 'ref', 'covering,nat', 'nat', '5', 'reports.4_nationality.nationality_id', '7932', NULL
我在每个nationality_id,txn_id,yrqtr上都有单独的索引。在我的大交易表中。而且只是我小桌子上的主键索引。
奇怪的是,没有连接的查询在结果中缺少一行!
答案 0 :(得分:1)
如果您的查找“菜单”列表只是所述的229行,并且它有一个唯一的键,并且您的菜单表上有索引(键,值),则连接可以忽略不计......特别是如果您的不管怎样,只能根据单个键查询结果。
对我来说,更大的问题是你的350万条记录。在229“菜单”项目中,每次平均返回超过15k的记录。而且我确信不是每个类别都是均衡的...有些可能有几百或几千个条目,有些可能有30k +条目。是否有其他标准可以返回较小的子集?显然没有足够的信息量化。
现在,在看到您修改后的帖子时,我发现您正在尝试获取聚合。否则,该表将针对历史数据进行修复。我建议根据每个国籍/年度基础进行汇总表。这样,如果期间在当前期间之前,您可以直接查询。如果是当前期间,则从生产中汇总总和。同样,由于交易不会在历史上发生变化,因此它们的计数也不会发生,您将从预先汇总表中立即得到响应。
<强>反馈强>
关于如何/何时实施汇总表。我会创建表格,其中包含您需要的相应列...国籍,期间(年/月)以及不同交易的相应计数等。
然后,我会针对所有现有数据预先汇总一次,但不包括当前期间(年/月)。现在,您已在摘要中确定了基线。
然后,在插入时为您的事务表添加一个触发器。然后,处理类似......(和注意,这不是实际的触发,但是要做什么的背景)
update summaryTable
set numTrans = numTrans + 1,
TotSales = TotSales + NEWENTRY.Sales,
TotUnits = TotUnits + NEWENTRY.Units
where
Nationality = NEWENTRY.Nationality
AND YrQtr = NEWENTRY.YrQtr
if # records affected by the update = 0
Insert into SummaryTable
( Nationality,
YrQtr,
NumTrans,
TotSales,
TotUnits )
values
( NEWENTRY.Nationality,
NEWENTRY.YrQtr,
1,
NEWENTRY.Sales,
NEWENTRY.Units )
现在,在将每条记录插入事务表后,您的聚合将始终在摘要表中同步。您始终可以查询此摘要表而不是完整的事务表。如果您从未有过针对给定国籍/ YrQtr的活动,则不会有任何记录。
答案 1 :(得分:0)
首先,将HAVING
移至WHERE
,以便查询的其余部分可以做的更少。其次,将nationality
的查询延迟到GROUP BY
:
SELECT
( SELECT nationality
FROM 4_nationality
WHERE nationality_id = t.nationality_id
) AS nationality,
COUNT(DISTINCT(txn_id)) as numtrans,
SUM(sales) as sales,
SUM(units) as units,
YrQtr
FROM 1_txns AS t
WHERE YrQtr LIKE :period
GROUP BY nationality_id;
如果可能,请避免使用外卡,只需执行YrQtr = :period
即可。这样可以INDEX(YrQtr, nationality_id)
获得更高的性能。