У нас есть клиентский сайт с базой данных SQL Server на 50 ГБ на сервере с ОЗУ более 100 ГБ.
Как приложение используется, SQL-сервер делает отличную работу по кэшированию db в память, но увеличение производительности от кеширования происходит в SECOND-времени, когда выполняется запрос, а не первый.
Чтобы попытаться максимизировать кеш-запросы при первом запуске запросов, мы написали proc, который выполняет итерацию по каждому индексу каждой таблицы во всей БД, выполняя это:
SELECT * INTO #Cache
FROM ' + @tablename + ' WITH (INDEX (' + @indexname + '))'
В попытке заставить большой, уродливый, изобретательный читать как можно больше данных. Мы планируем запускать каждые 15 минут, и он отлично работает в целом.
Не обсуждая другие узкие места, спецификации оборудования, планы запросов или оптимизацию запросов, есть ли у кого-нибудь лучшие идеи о том, как выполнить эту же задачу?
ОБНОВЛЕНИЕ
Спасибо за предложения. Удален "INTO #Cache". Протестировано, и это не повлияло на заполнение буфера.
Добавлено: вместо Select *, я выбираю ТОЛЬКО ключи из Индекса. Это (очевидно) является более точным и намного быстрее.
Добавлено: индексы чтения и кэша.
Здесь текущий код: (надеюсь, это полезно для кого-то еще)
CREATE VIEW _IndexView
as
-- Easy way to access sysobject and sysindex data
SELECT
so.name as tablename,
si.name as indexname,
CASE si.indid WHEN 1 THEN 1 ELSE 0 END as isClustered,
CASE WHEN (si.status & 2)<>0 then 1 else 0 end as isUnique,
dbo._GetIndexKeys(so.name, si.indid) as Keys,
CONVERT(bit,CASE WHEN EXISTS (SELECT * FROM sysconstraints sc WHERE object_name(sc.constid) = si.name) THEN 1 ELSE 0 END) as IsConstraintIndex
FROM sysobjects so
INNER JOIN sysindexes si ON so.id = si.id
WHERE (so.xtype = 'U')--User Table
AND ((si.status & 64) = 0) --Not statistics index
AND ( (si.indid = 0) AND (so.name <> si.name) --not a default clustered index
OR
(si.indid > 0)
)
AND si.indid <> 255 --is not a system index placeholder
UNION
SELECT
so.name as tablename,
si.name as indexname,
CASE si.indid WHEN 1 THEN 1 ELSE 0 END as isClustered,
CASE WHEN (si.status & 2)<>0 then 1 else 0 end as isUnique,
dbo._GetIndexKeys(so.name, si.indid) as Keys,
CONVERT(bit,0) as IsConstraintIndex
FROM sysobjects so
INNER JOIN sysindexes si ON so.id = si.id
WHERE (so.xtype = 'V')--View
AND ((si.status & 64) = 0) --Not statistics index
GO
CREATE PROCEDURE _CacheTableToSQLMemory
@tablename varchar(100)
AS
BEGIN
DECLARE @indexname varchar(100)
DECLARE @xtype varchar(10)
DECLARE @SQL varchar(MAX)
DECLARE @keys varchar(1000)
DECLARE @cur CURSOR
SET @cur = CURSOR FOR
SELECT v.IndexName, so.xtype, v.keys
FROM _IndexView v
INNER JOIN sysobjects so ON so.name = v.tablename
WHERE tablename = @tablename
PRINT 'Caching Table ' + @Tablename
OPEN @cur
FETCH NEXT FROM @cur INTO @indexname, @xtype, @keys
WHILE (@@FETCH_STATUS = 0)
BEGIN
PRINT ' Index ' + @indexname
--BEGIN TRAN
IF @xtype = 'V'
SET @SQL = 'SELECT ' + @keys + ' FROM ' + @tablename + ' WITH (noexpand, INDEX (' + @indexname + '))' --
ELSE
SET @SQL = 'SELECT ' + @keys + ' FROM ' + @tablename + ' WITH (INDEX (' + @indexname + '))' --
EXEC(@SQL)
--ROLLBACK TRAN
FETCH NEXT FROM @cur INTO @indexname, @xtype, @keys
END
CLOSE @cur
DEALLOCATE @cur
END
GO