Обновить
0
0

Пользователь

Отправить сообщение

Тоже самое и у меня было. 4 года назад в новую КВ купил разных светодиодных ламп. Гаусы все подсохли первыми в первый же год (лампы разной мощности), хотя стоили значительно дороже конкурентов. Самые стойкие оказались какие-то самые дешёвые Feron, до сих пор большинство ламп этого бренда работают. У них просто выгорает люминофор и светят со временем слабее.

Мы используем ноутбуки и git, у нас есть итерации бранят и continuous delivery. Такой вариант всех устраивает.

Databricks + Azure DevOps.

Данные сразу будут записаны в LOB хранилище. И это правильно, т.к. в большинстве случаев если мы читаем var...(max) поле, то мы читаем его полностью, значит нет смысла часть его хранить в таблице а часть в LOB. И второе, достаточно часто в запросах читаются все поля кроме var...(max), т.е. больше поля читаются как правило точеными запросами, типа получения объекта по его идентификатору. А значит большинство запросов выигрывают в случае включения этой опции, т.к. читая страницы таблицы мы не читаем багаж в виже части LOB полей.

Из доков:

https://docs.microsoft.com/en-us/sql/relational-databases/system-stored-procedures/sp-tableoption-transact-sql?view=sql-server-ver15#arguments

large value types out of row

1 = varchar(max)nvarchar(max)varbinary(max)xml and large user-defined type (UDT) columns in the table are stored out of row, with a 16-byte pointer to the root.

0 = varchar(max)nvarchar(max)varbinary(max)xml and large UDT values are stored directly in the data row, up to a limit of 8000 bytes and as long as the value can fit in the record. If the value does not fit in the record, a pointer is stored in-row and the rest is stored out of row in the LOB storage space. 0 is the default value.

Можно ставить "метку" на запрос.

В данном примере для n/a значения будет другой текст запроса, а значит и другой план (даже коммент в текте запроса меняет его хеш).


create or alter procedure dbo.SmartGetValDyn
	@val varchar(32)
as
	declare @Sql nvarchar(max) = concat(
	iif(@val='n/a', '-- n/a query', ''),
	'		
		select *
		from dbo.Unlucky
		where VAL = @val
	')
	print @Sql
	exec sys.sp_executesql @Sql, N'@val varchar(32)', @val = @val
go

exec dbo.SmartGetValDyn @val = 'n/a'
exec dbo.SmartGetValDyn @val = '1val'
go

Как видите, тут два разных плана. Причем их будет только 2, а не миллион как с инлайном где также присутствует проблема sql injection.

К примеру в таблице 15 столбцов, один из столбцов (DataStatus) содержит 50% одинаковых значений (значение Completed), и что вы предлагаете, как нормализовать такую таблцу?

Перенести Completed записи в другую таблицу? А потом мучиться с отчетами, и с процессами по переносу данных и одной таблиы в другую. Может кто-то захочит перевести статус в Active? А если нужно обновить данные другого столбца то придется обновлять две таблицы, делать два запроса, писать "умный" DataAccess. В общем это проблема из ничего.

Нормализация хороша в теории, на практике выше 3-й нормальной формы заморачиватся не стоит.

Все нормально работает. Просто нужно указывать точный фильтр в запросе, такой же как и в фильтрованном индексе. Будет работать и для сложных условий по нескольким столбцам тоже.

create index IDX_VAL on Unlucky (VAL) where VAL <> 'n/a'
go

create or alter procedure SmartGetVal
	@val varchar(32)
as
	if @val = 'n/a'
		select *
		from dbo.Unlucky
		where VAL = 'n/a' -- not @val!!!
	else
		select *
		from dbo.Unlucky with ( index = IDX_VAL )
		where VAL = @val
		  and VAL <> 'n/a'
go

exec dbo.SmartGetVal @val = '1val'
go

print @@version
Microsoft SQL Server 2017 (RTM-GDR) (KB4583456) - 14.0.2037.2 (X64) 
	Nov  2 2020 19:19:59 
	Copyright (C) 2017 Microsoft Corporation
	Developer Edition (64-bit) on Windows 10 Pro 10.0 <X64> (Build 19044: )

Еще пара моментов которые надо учитывать.

  1. При использовании типа varchar(n) / nvarchar(n), sql server предполагает что средний размет строки будет n/2, и исходя из этого выделяет память для выполнения запросов. Поэтому при выборе значения n идеальным будет удвоенное значение средней длины строк хранящихся в этом столбце.
    Для varcha(max) / nvarchar(max) он предполагает что средняя длина равна 4000 символам, т.е. если вы скажем будете хранить строки размером в 100 символов в таком столбце, то памяти будет выделяться в 40 раз больше чем нужно для запроса, что в свою очередь плохо скажется на производительности.

  2. Скажем у вас в таблице есть столбцы с данными, и один или несколько столбцов varcha(max) / nvarchar(max). По умолчанию данные varcha(max) / nvarchar(max) хранятся IN_ROW если объем их меньше 8000 байт.
    Иногда имеет смысл поменять это поведение, и сразу хранить все эти данные как LOB_DATA. Это улучшит производительность запросов которые не читают LOB столбцы из таблицы.
    Такое поведение можно включить через опцию large value types out of row

    exec sys.sp_tableoption
    	  @TableNamePattern = 'dbo.TableName'
      , @OptionName = 'large value types out of row'
      , @OptionValue = '1'

Не работает так, как вы описываете. Без кластерного индекса такое же поведение.

Все также висит X (exclusive) блокировка на некластерном индексе во время апдейта, и она не совместима с S (shared) блокировкой при чтении, вторая сессия ждет завершения первой.

Может быть описываемое вами поведение это просто баг/фича в какой-нибудь старой версии sql server?

Тестировалось на:
Microsoft SQL Server 2019 (RTM-GDR) (KB4583458) - 15.0.2080.9 (X64)   Nov  6 2020 16:50:01   
Copyright (C) 2019 Microsoft Corporation  Developer Edition (64-bit) 
on Windows 10 Pro 10.0 <X64> (Build 19044: ) 

Я правильно понимаю что мы говорим о двух сессиях, первая обновляет строку, вторая читает ее в обычном read committed?

-- table definition
create table dbo.test1 (
    id int primary key clustered
  , data1 varchar(100)
  , data2 char(100)
  , data3 nchar(100)  
)
go

create index idx_test1_allincluded 
on dbo.test1 ( id ) include ( data1, data2, data3 )
go

insert into dbo.test1 ( id, data1, data2, data3 )
values (1, 'data1 1', 'data2 1', 'data3 1')
     , (2, 'data1 2', 'data2 2', 'data3 2')
     , (3, 'data1 3', 'data2 3', 'data3 3')
go

-- session 1
update dbo.test1 set data1 = 'new data 1' where id = 2 
go

-- session 2
select * from dbo.test1 where id = 2
go

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

Не за компом. Вот это разве не сработает?

select *
from Unlucky with (index=val)
where val<>'n/a' 
  and val=@val

ещё индексы на вьюхах в онлайне не построить.

Напишите пожалуйста подробнее. Что значит отключение версионирования? И какой лок накладывается? Впервые слышу про эту проблему...

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность