Tengo una tabla que contiene una gran cantidad de datos, donde nos preocupa especialmente el campo date
. La razón de esto es que el volumen de datos simplemente subió ~ 30x, y las viejas formas se desmoronarán pronto. La consulta espero que me puede ayudar a optimizar las necesidades a:Intentando optimizar una consulta que selecciona un "registro aproximado aproximado"
- tomar una lista de fechas (generada por una función con valores de tabla basada CTE)
- recuperar un registro único para cada una de esas fechas
- basado en una definición de 'más cercana'
Por ejemplo, la tabla actual contiene datos de cada 5 segundos (+/- un poco) intervalos. Necesito muestrear esa tabla y obtener el registro que más se acerca a un intervalo de 30 segundos.
Lo que tengo ahora funciona bien. Simplemente tengo curiosidad si hay una forma de optimizarlo más. Si puedo hacerlo en Linq To SQL, eso también sería genial. Incluso estoy interesado en sugerencias sobre índices, dada la cantidad de valores de fecha (~ 2 millones de filas mínimas).
declare @st datetime ; set @st = '2012-01-31 05:05:00';
declare @end datetime ; set @end = '2012-01-31 05:10:00';
select distinct
log.* -- id,
from
dbo.fn_GenerateDateSteps(@st, @end, 30) as d
inner join lotsOfLogData log on l.Id = (
select top 1 e.[Id]
from
lotsOfLogData as log -- contains data in 5 second intervals
where
log.stationId = 1000
-- search for dates in a certain range
AND utcTime between DateAdd(s, -10, dt) AND DateAdd(s, 5, dt)
order by
-- get the 'closest'. this can change a little, but will always
-- be based on a difference between the date
abs(datediff(s, dt, UtcTime))
)
-- updated the query to be correct. stadionId should be inside the subquery
La estructura de la tabla de lotsOfLogData está debajo. Hay relativamente pocos ID de estación (quizás 50), pero muchos registros para cada uno. Conocemos la identificación de la estación cuando consultamos.
create table ##lotsOfLogData (
Id bigint identity(1,1) not null
, StationId int not null
, UtcTime datetime not null
-- 20 other fields, used for other calculations
)
fn_GenerateDateSteps devuelve un conjunto de datos como éste, para los parámetros dados:
[DT]
2012-01-31 05:05:00.000
2012-01-31 05:05:30.000
2012-01-31 05:06:00.000
2012-01-31 05:06:30.000 (and so on, every 30 seconds)
me han hecho esto con una tabla temporal, así, de esta manera, sino que salió sólo un poco un poco más caro.
declare @dates table (dt datetime, ClosestId bigint);
insert into @dates (dt) select dt from dbo.fn_GenerateDateSteps(@st, @end, 30)
update @dates set closestId = (-- same subquery as above)
select * from lotsOfLogData inner join @dates on Id = ClosestId
Editar: se ha corregido hasta
Got 200K + filas para trabajar ahora. Lo intenté en ambos sentidos, y la cruz se aplica con un índice apropiado (id/time + includes (... todas las columnas ...) funcionó bien. Sin embargo, terminé con la consulta que comencé, usando un más simple (y existente) . índice de [id + tiempo] La consulta más ampliamente comprensible por qué es que se establecieron en que uno Tal vez todavía hay una mejor manera de hacerlo, pero no puedo verlo:. D
-- subtree cost (crossapply) : .0808
-- subtree cost (id based) : .0797
-- see above query for what i ended up with
La aplicación cruzada quiere que haga un índice en la estaciónid/hora que también incluye * todos * los otros datos en la tabla. Sin el índice, funciona exactamente igual que la consulta simple, por lo que en este caso la cruz no va a funcionar :) Sin embargo, ni siquiera lo sabía, ¡así que gracias! –
Ah, y tuve un error en esa consulta;) * Estoy * obligado * a poner el ID de la estación en la subconsulta porque de lo contrario coincidiré con cualquier ID de la estación que esté dentro del rango. Después de hacer eso, se usa el índice adecuado y todo es súper rápido (ish) –
@AndrewBacker: ausente, pero gracias por mantenernos informados. –