Комментарий к решению Emtucifor (поскольку я не могу делать регулярные комментарии)
Мне нравится это решение, но есть некоторые комментарии, как его можно улучшить (в данном конкретном случае).
Это невозможно сделать, если у вас все в одной таблице, но наличие нескольких таблиц, как в решении Джона Сандерса, изменит ситуацию к лучшему.
Поскольку мы имеем дело с числами в таблице [CandyPreferences], мы можем использовать математическую операцию вместо конкатенации, чтобы получить максимальное значение.
Я предлагаю PreferenceFactor быть десятичным, а не вещественным, так как я считаю, что здесь нам не нужен размер реального типа данных, и еще дальше я бы предложил десятичное число (n, n), где n <10, чтобы хранить только десятичную часть в 5 байтов. Предположим, что десятичного числа (3,3) достаточно (1000 уровней коэффициента предпочтения), мы можем сделать простое </p>
PackedData = Max (PreferenceFactor + CandyID)
Далее, если мы знаем, что у нас меньше 1 000 000 CandyID, мы можем добавить приведение как:
PackedData = Max (приведение (PreferenceFactor + CandyID как десятичное число (9,3)))
разрешение серверу sql использовать 5 байтов во временной таблице
Распаковка легко и быстро с использованием функции пола.
Niikola
- ДОБАВЛЕНО ПОЗЖЕ ---
Я протестировал оба решения, Джона и Эмтуцифора (модифицированные для использования структуры Джона и использования моих предложений). Я тестировал также с и без соединений.
Решение Emtucifor явно выигрывает, но поля не велики. Может быть иначе, если SQL-серверу нужно было выполнить некоторые физические чтения, но во всех случаях они были равны 0.
Вот вопросы:
SELECT
[PersonID],
CandyID = Floor(PackedData),
PreferenceFactor = Cast(PackedData-Floor(PackedData) as decimal(3,3))
FROM (
SELECT
[PersonID],
PackedData = Max(Cast([PrefernceFactor] + [CandyID] as decimal(9,3)))
FROM [z5CandyPreferences] With (NoLock)
GROUP BY [PersonID]
) X
SELECT X.PersonID,
(
SELECT TOP 1 CandyID
FROM z5CandyPreferences
WHERE PersonID=X.PersonID AND PrefernceFactor=x.HighestPreference
) AS TopCandy,
HighestPreference as PreferenceFactor
FROM
(
SELECT PersonID, MAX(PrefernceFactor) AS HighestPreference
FROM z5CandyPreferences
GROUP BY PersonID
) AS X
Select p.PersonName,
c.Candy,
y.PreferenceFactor
From z5Persons p
Inner Join (SELECT [PersonID],
CandyID = Floor(PackedData),
PreferenceFactor = Cast(PackedData-Floor(PackedData) as decimal(3,3))
FROM ( SELECT [PersonID],
PackedData = Max(Cast([PrefernceFactor] + [CandyID] as decimal(9,3)))
FROM [z5CandyPreferences] With (NoLock)
GROUP BY [PersonID]
) X
) Y on p.PersonId = Y.PersonId
Inner Join z5Candies c on c.CandyId=Y.CandyId
Select p.PersonName,
c.Candy,
y.PreferenceFactor
From z5Persons p
Inner Join (SELECT X.PersonID,
( SELECT TOP 1 cp.CandyId
FROM z5CandyPreferences cp
WHERE PersonID=X.PersonID AND cp.[PrefernceFactor]=X.HighestPreference
) CandyId,
HighestPreference as PreferenceFactor
FROM ( SELECT PersonID,
MAX(PrefernceFactor) AS HighestPreference
FROM z5CandyPreferences
GROUP BY PersonID
) AS X
) AS Y on p.PersonId = Y.PersonId
Inner Join z5Candies as c on c.CandyID=Y.CandyId
И результаты:
TableName nRows
------------------ -------
z5Persons 200,000
z5Candies 150,000
z5CandyPreferences 497,445
Query Rows Affected CPU time Elapsed time
--------------------------- ------------- -------- ------------
Emtucifor (no joins) 183,289 531 ms 3,122 ms
John Saunders (no joins) 183,289 1,266 ms 2,918 ms
Emtucifor (with joins) 183,289 1,031 ms 3,990 ms
John Saunders (with joins) 183,289 2,406 ms 4,343 ms
Emtucifor (no joins)
--------------------------------------------
Table Scan count logical reads
------------------- ---------- -------------
z5CandyPreferences 1 2,022
John Saunders (no joins)
--------------------------------------------
Table Scan count logical reads
------------------- ---------- -------------
z5CandyPreferences 183,290 587,677
Emtucifor (with joins)
--------------------------------------------
Table Scan count logical reads
------------------- ---------- -------------
Worktable 0 0
z5Candies 1 526
z5CandyPreferences 1 2,022
z5Persons 1 733
John Saunders (with joins)
--------------------------------------------
Table Scan count logical reads
------------------- ---------- -------------
z5CandyPreferences 183292 587,912
z5Persons 3 802
Worktable 0 0
z5Candies 3 559
Worktable 0 0