繁体   English   中英

mySQL查询分组记录的前N个条目

[英]mySQL query for top N entries of a grouped records

我是MySql和一般数据库的新手。 我有一个查询,我通过在线资源和跟踪和错误的片段一起构建。 它真的很慢(27秒),我认为它可以优化。 也许有人可以帮我解决这个问题。

这是mySQL的数据结构 - 数据库。 版本5.1.51-0

|- purchaseID -|- customerID -|- emotionID -|- customerCountryCode -|- customerContinentCode-|
|     1        |     2345     |     0       |        US             |            NA          |
|     2        |     2345     |     3       |        US             |            NA          |
|     3        |     4456     |     0       |        UK             |            EU          |
|     3        |     4456     |     5       |        UK             |            EU          |
|     4        |     4456     |     2       |        UK             |            EU          |
|     5        |     4456     |     2       |        UK             |            EU          |
|     6        |     1234     |     0       |        US             |            NA          |
|     7        |     6678     |     0       |        US             |            NA          |
|     8        |     9900     |     0       |        US             |            NA          |
|     9        |     3334     |     0       |        US             |            NA          |    
|     10       |     3334     |     4       |        US             |            NA          |

该数据库用于保存所有已完成的购买。 对于每次购买,他来自的customerID ,国家和大陆都会被保存。 顾客还可以从一组6种情绪中评价他的购买情况。 (快乐,失望,......)他选择的情感被保存为情感emotionID

所以现在我需要一个查询来获取具有百分比信息的特定emotionID客户。 假设我查找了emotionID = 0这是我想得到的:

|- customerID -|- emotionPercent -|
|     1234     |        100       |     
|     6678     |        100       |     
|     9900     |        100       | 
|     2345     |        50        |     
|     3334     |        50        | 
|     4456     |        25        |    

我正在使用此查询:

SELECT customers.customerID, Count( customers.emotionID ) / C.totalPeople * 100.0 AS emotionPercent 
FROM `customers` 
INNER JOIN 

    (SELECT customers.customerID, Count( customers.emotionID ) AS totalPeople
    FROM `customers` 
    GROUP BY customerID) C 

ON customers.customerID = C.customerID 
WHERE customers.emotionID = 0 
GROUP BY customers.customerID 
ORDER BY emotionPercent DESC 
LIMIT 0,6

我已经搜索了答案,但额外的百分比计算让我失望。 我找到了一些解决方案,需要填充某种临时表,但我无法使其工作。

问题是:现在,数据库中有140,000个条目,此查询大约需要27秒。 这可能是对的吗? 使用SQL - Server会显着提高速度吗?

我没有得到的是:要求世界上最幸福的国家快速闪电(0.4秒),但结构上与第一个查询类似(27秒):

SELECT customers.customerCountryCode, Count( customers.emotionID ) / C.totalPeople * 100.0 AS emotionPercent 
FROM `customers` 
INNER JOIN 

    (SELECT customers.customerCountryCode, Count( customers.emotionID ) AS totalPeople
    FROM `customers` 
    GROUP BY customerCountryCode) C 

ON customers.customerCountryCode = C.customerCountryCode 
WHERE customers.emotionID = 0 
GROUP BY customers.customerCountryCode 
ORDER BY emotionPercent DESC 
LIMIT 0,6

当我将此示例中的INNER QueryGROUP BY更改为customerID ,查询也将永远占用。 所以这是由customerID分组导致问题。 但为什么?

customerCountryCode定义为varchar(2) customerID是一个int(11) 这是否会导致查询性能的巨大差异? 是否有更合适的变量类型? customerID最多可包含8个号码。

很多问题! 感谢阅读和任何帮助!

首先,如果您认为数据库中的条目会膨胀,或者您的条目很高且服务器速度很慢,恕我直言,您可能希望预处理数据并将其存储到具有汇总结果的另一个数据库,这样,您就不必一遍又一遍地请求相同的过程。 另外,尝试为您的应用使用缓存插件。 php或ehcache在j2ee上的memcache将是安全的赌注。

您的问题可能是您正在使用子查询。 由于子查询不使用也不设置索引,因此它们使用最慢的连接方法(即全表扫描)。 我没有足够的经验来提供仅限SQL的解决方案,因此我建议您将查询分解为两个单独的调用。

  1. 获得每个客户的平均情绪并选择前6个,保存为哈希或对象。
  2. 通过WHERE custumerID IN (id1, id2, id3, etc)获取这6个客户

虽然这可能不是最漂亮的解决方案,但您可以避免使用无索引子查询(以及非常慢的全表扫描)。

谢谢你的帮助!

来自mySQL论坛的人建议添加一些索引:

ALTER TABLE customers
  ADD KEY idx_country_emid (customerCountryCode, emotionID),
  ADD KEY idx_emid_custid (emotionID, customerID);

查询时间从27秒降至0.1秒。 ;)

此外,对于内部查询,您可以编写

(SELECT customers.customerCountryCode, Count( * ) AS totalPeople
    FROM `customers` 
    GROUP BY customerCountryCode) C 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM