Super Lloyd Ответов: 1

Вопрос многомерной индексации


Сейчас я создаю таблицу, которая содержит информацию о грузовике сверхурочно,
мой вопрос: Чего я хочу, так это двоякого:

1. напишите запрос, который получит последнюю запись для каждого грузовика (я создаю таблицу прямо сейчас, у меня нет даты, трудно проверить)

2. Убедитесь, что я создаю правильный индекс, который сделает этот запрос быстрым (у меня есть некоторые сомнения в том, что многомерный индекс (дата и truckID) может успешно использовать оператор сравнения)

3. (необязательно) как написать этот запрос с помощью EF

Что я уже пробовал:

Мой стол выглядит так
create table TruckLocation (
  ID bigint identity (1, 1),
  TruckID int not null,
  timestamp datetime2 not null,
  -- blablabla other data, ex:
  latitude real not null,
  longitude real not null
)

И да я тоже использую geometry тип, это не мой вопрос.


Для текущего местоположения я придумал этот запрос
select * 
from dbo.TruckLocations LOC
where [timestamp] = (select max([timestamp]) from dbo.TruckLocations where TruckID = LOC.TruckID)

кажется, работает...

Но я хочу убедиться, что он работает быстро!
а как насчет этого индекса? (вот в чем настоящий вопрос)

CREATE NONCLUSTERED INDEX [IDX_TRUCKLOCATIONS_TIMESTAMP] ON [dbo].[TruckLocations]
(
	[TruckID] ASC,
	[timestamp] desc
)
GO


Наконец, как мне написать этот запрос в EF (Entity Framework)?
было бы неплохо избежать хранимой процедуры....

Я придумал это, анализатор запросов, кажется, все в порядке....
var query =
    from p in db.TruckLocations
    where p.timestamp == db.TruckLocations.Where(x => x.TruckID == p.TruckID).Max(x => x.timestamp)
    select p
    ;

удивительное дело делать OrderByDescending(timestamp).Take(1), но анализатор запросов "выглядит" хуже всего... (не очень хорошо читает анализатор запросов)

1 Ответов

Рейтинг:
5

Wendelius

Что меня смущает в вашем запросе, так это то, что вы выбираете все строки из TruckLocations. Я бы предположил, что таблица вождения будет содержать только грузовики, а не места, так как вы получаете последнюю позицию...

Поэтому для того, чтобы сделать его более эффективным, должен ли запрос быть чем-то вроде

select ... 
from dbo.Trucs t INNER JOIN dbo.TruckLocations LOC on LOC.TruckID = t.TruckID
WHERE LOC.[timestamp] = (select max(LOC2.[timestamp])
                         from dbo.TruckLocations LOC2 
                         where LOC2.TruckID = t.TruckID)


Если бы это было так, то предложенный вами индекс работал бы просто отлично. Немного большей скорости можно достичь, выполнив следующие действия:
- использование кластеризации в индексе таким образом, чтобы метки времени были физически упорядочены. Однако обратите внимание, что это увеличивает время вставки и обновления записей
- определение индекса как уникального, если невозможно иметь две записи для одного грузовика в один и тот же момент времени
- если вы извлекаете только несколько других столбцов из таблицы TruckLocations, подумайте о добавлении этих столбцов в индекс, чтобы получить индекс покрытия, см. Создание индексов с включенными столбцами[^]

Что касается создания запроса, то если вы хотите избежать процедуры, почему бы не создать для нее представление или позволить ей быть в простом SQL. Что я боюсь с LINQ, так это то, что способ, которым он фактически создает SQL-оператор, может изменяться с течением времени, вызывая изменения в планах выполнения.

Надеюсь, я правильно понял ваш вопрос и не совсем бездорожье :)


Super Lloyd

проблема заключается в том, что вместо того, чтобы иметь 2 таблицы (исторические местоположения всех грузовиков и текущее местоположение всех грузовиков) Я получил только 1 таблицу (историческую) и пытаюсь получить текущее местоположение всех грузовиков, извлекая последнюю запись для каждого грузовика.

Да! Я сделал индекс уникальным!
Я не могу кластеризировать его, так как у меня есть первичный ключ (ID), но.. это интересная идея!

Вид (для текущих местоположений) Эй? Отличная идея! :)
Я хотел избежать SP и не любить сложный вид... но этот такой осмысленный и простой! Да! :)

Wendelius

Рад, если это было полезно. С водительским столом я на самом деле не имел в виду, что вы будете разделять текущие и исторические места. Только то, что у вас будет таблица поиска, содержащая одну строку для каждого грузовика и его первичный ключ (truckid).

Я подозреваю, что если бы у вас была такая таблица и вы использовали бы ее в запросе, база данных могла бы использовать ее в качестве таблицы поиска и, возможно, сделать индексное соединение, чтобы быстрее получить местоположения.

Возможно, стоит попробовать...