Эффективное назначение процентиля / ранга в MYSQL - PullRequest
3 голосов
/ 17 августа 2011

У меня есть пара очень больших таблиц (более 400 000 строк), которые выглядят следующим образом:

+---------+--------+---------------+
| ID      | M1     | M1_Percentile |
+---------+--------+---------------+
| 3684514 | 3.2997 | NULL          |
| 3684515 | 3.0476 | NULL          |
| 3684516 | 2.6499 | NULL          |
| 3684517 | 0.3585 | NULL          |
| 3684518 | 1.6919 | NULL          |
| 3684519 | 2.8515 | NULL          |
| 3684520 | 4.0728 | NULL          |
| 3684521 | 4.0224 | NULL          |
| 3684522 | 5.8207 | NULL          |
| 3684523 | 6.8291 | NULL          |
+---------+--------+---------------+...about 400,000 more

Мне нужно присвоить каждой строке в столбце M1_Percentile значение, представляющее «процент строк со значениями M1, равными или меньшими M1 значению текущей строки»

Другими словами, мне нужно:

enter image description here

Я реализовал это успешно, но это слишком далеко. Если бы кто-нибудь мог создать более эффективную версию следующего кода, я был бы очень признателен!

UPDATE myTable AS X JOIN (
SELECT
  s1.ID, COUNT(s2.ID)/ (SELECT COUNT(*) FROM myTable) * 100 AS percentile
FROM
  myTable s1 JOIN myTable s2 on (s2.M1 <= s1.M1)
GROUP BY s1.ID
ORDER BY s1.ID) AS Z 
ON (X.ID = Z.ID) 
SET X.M1_Percentile = Z.percentile;

Это (правильный, но медленный) результат вышеприведенного запроса, если количество строк ограничено теми, которые вы видите (10 строк):

+---------+--------+---------------+
| ID      | M1     | M1_Percentile |
+---------+--------+---------------+
| 3684514 | 3.2997 |            60 |
| 3684515 | 3.0476 |            50 |
| 3684516 | 2.6499 |            30 |
| 3684517 | 0.3585 |            10 |
| 3684518 | 1.6919 |            20 |
| 3684519 | 2.8515 |            40 |
| 3684520 | 4.0728 |            80 |
| 3684521 | 4.0224 |            70 |
| 3684522 | 5.8207 |            90 |
| 3684523 | 6.8291 |           100 |
+---------+--------+---------------+

Для получения одинаковых результатов для всех 400 000 строк требуется больше времени.

Ответы [ 2 ]

3 голосов
/ 17 августа 2011

Я не могу проверить это, но вы можете попробовать что-то вроде:

update table t
set mi_percentile = (
    select count(*)
    from table t1
    where M1 < t.M1 / (
        select count(*)
        from table));

ОБНОВЛЕНИЕ:

update test t
set m1_pc = (
    (select count(*) from test t1 where t1.M1 < t.M1) * 100 /
    ( select count(*) from test));

Это работает в Oracle (единственная база данных, которая у меня есть).Я помню, как получил эту ошибку в MySQL.Это очень раздражает.

1 голос
/ 17 августа 2011

Справедливое предупреждение: MySQL не является моей родной средой.Однако после небольшого исследования я думаю, что следующий запрос должен быть работоспособным:

UPDATE myTable AS X 
JOIN ( 
  SELECT  X.ID, (
      SELECT  COUNT(*)
      FROM    myTable X1
      WHERE   (X.M1, X.id) >= (X1.M1, X1.id) as Rank)
  FROM myTable as X
) AS RowRank
ON (X.ID = RowRank.ID)
CROSS JOIN (
  SELECT COUNT(*) as TotalCount 
  FROM myTable 
) AS TotalCount
SET X.M1_Percentile = RowRank.Rank / TotalCount.TotalCount;
...