Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2003.12.19;
Скачать: [xml.tar.bz2];

Вниз

как получить будущее значение ID после опреации Insert?   Найти похожие ветки 

 
DBDev   (2003-11-24 13:10) [0]

Нужно для добавления (вставки) дочерних объектов в сеансе INsert-a родительского. Надо же корректно присвоить полям дочерних объектов поле РодительID...
MSSQL Server + ADO.


 
Hooch   (2003-11-24 13:20) [1]

// вставили родителя
@ParentID = @@IDENTITY
// вставляем детей


 
Michail Dalakov   (2003-11-24 13:30) [2]

Проблема c генераторами у MSSQL известна с давних времен.
Тем не менее рекомендую не пользоваться автоинкрементируемыми
полями а получать уникальные значения заранее. Вариантов существует много, после работы например с oracle или другими СУБД, процесс получения уникальных значений в MSSQL приводит в шоковое состояние, но тем не менее прекрасно работает


 
Nikolay M.   (2003-11-24 14:28) [3]


> Проблема c генераторами у MSSQL известна с давних времен

А если не секрет, что такое генератор в MSSQL?

По сабжу: на рсдн найди статью Капустина Перенос приложений с одной СУБД на другую.


 
Stas   (2003-11-24 14:49) [4]

Может это поможет ?

uses ADOint;
AdoDataSet.CursorLocation:=clServer;
ADODataSet1.Properties["Update Resync"].Value:= adResyncAutoIncrement;

Подробнее:
http://www.delphikingdom.com/helloworld/ado02.htm


 
Shirson   (2003-11-24 14:55) [5]

После вставки строки с родителем, в триггере пишешь
Set @ParentID = SCOPE_IDENTITY()
Собственно всё.

>Hooch © (24.11.03 13:20) [1]

@@IDENTITY делать не стоит. Это глобальная байда.

>Michail Dalakov (24.11.03 13:30) [2]
Проблема c генераторами у MSSQL известна с давних времен.

Не поделитесь?


 
Michail Dalakov   (2003-11-24 15:58) [6]

To Shirson
Поделюсь.
Перед вставкой записи требуется получить уникальное значение
ключа, никто не отрицает что это возможно, я сам это неоднократно
делал, но такого простого решения как делается например в IB:
NewID = Gen_ID(ID, 1) или в oracle: select ID.NextVal ID from DUAL в MSSQL нет. Почему? А потому что вместо генераторов IB или
поледовательностей oracle в MSSQL предусмотренны автоинкрементируемые поля.
Уникальные значения я получал следующим образом:
хранимая процедура(ниже) которой передавалось имя приводимой ниже таблицы возвращала это значение

CREATE PROCEDURE [dbo].[GetId]
@GenName VARCHAR(50) AS
DECLARE @SQLString NVARCHAR(1000)
DECLARE @ID int
SET @SQLString = N"insert into " +@GenName+ " (tmp) values ("""")
SET @ID=(SELECT value FROM "+@GenName+" where value=scope_identity() )
DELETE FROM "+ @GenName+" where value=scope_identity() "
exec sp_executesql @SQLString, N"@ID int out", @ID = @ID out
return @ID
GO

create table GEN_ID(
value int IDENTITY (1, 1) NOT NULL,
tmp varchar(1)
)
GO

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


 
SergSuper   (2003-11-24 16:23) [7]

Если не смущает guid, то можно использовать select newid()

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


 
Michail Dalakov   (2003-11-24 22:39) [8]

To SergSuper
Сколько байт занимает guid, и это для каждой таблицы!

Разница есть, ну например сколько бы триггеров пришлось написать
Shirson для достаточно большой DB, и это всего лишь для получения
ID
Другой вариант хитрая и частая репликация более мелких баз данных в некую глобальную, т.е. приходят записи со своими ID, которые должны слиться с другими некоторой таблицы, конечно задача решается, но насколько удобны в данном случае автоинкпементируемые поля?


 
panov   (2003-11-24 22:58) [9]

А как насчет получения ID от текущего времени?


 
Johnmen   (2003-11-24 23:52) [10]

>panov © (24.11.03 22:58)

Если ID есть интегер, то не более чем на ~50 лет.
При многопользовательской работе могут быть накладки...:)


 
Shirson   (2003-11-25 08:56) [11]

>Michail Dalakov (24.11.03 15:58) [6]
Перед вставкой записи требуется получить уникальное значение
ключа, никто не отрицает что это возможно...

Э... что-то я с утра туго соображаю... А зачем его получать ДО вставки?
Если это родительский id, требуемый для детей, то сначала вставляем парента, потом чилдренов. А не наоборот.

Или я где-то, что-то пропустил?


 
SergSuper   (2003-11-25 10:53) [12]

> Michail Dalakov
guid занимает 16 байт, а int - 4. Обычно эти размеры гораздо меньше размера остальных полей таблицы. Так что размеры - не аргумент. Основной недостаток guid - их трудно прочитать, записать, продиктовать по телефону и т.д.

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

Ну и наконец плакать хочется видя Вашу процедуру GetId.

Я бы так написал:


create table GEN_ID(
gen varchar(33),
counter int default(0)
)
GO

CREATE PROCEDURE GetId
@GenName VARCHAR(50) AS
DECLARE @ID int
update GEN_ID set @ID=counter=counter+1 where gen=@GenName
return @ID
GO


Чтоб создать "генератор" надо просто вставить его имя в GEN_ID, создавать таблицы не надо.


 
KSergey   (2003-11-25 12:35) [13]

[5] Shirson © (24.11.03 14:55)
После вставки строки с родителем, в триггере пишешь
Set @ParentID = SCOPE_IDENTITY()
Собственно всё.


Все, но не забывайте уточнять, что это только начиная с MS SQL 2000

Проблема c генераторами у MSSQL известна с давних времен.
Не поделитесь?


Видимо, вы начали с MS SQL 2000
Потому и не в курсе. Ранее было только @@IDENTITY


 
hCat   (2003-11-25 14:00) [14]

Попробую вставить в этот разговор и свои пять копеек

> или в oracle: select ID.NextVal ID from DUAL

Последняя мода состоит вообще в отказе от такого вызова. Вместо предлагаемой конструкции:
select ID.NextVal into :ID from DUAL;
insert into tab1(ID, ...) values (:ID, ...);
insert into tab2(Parent_ID, ...) values (:ID, ...);
быстрее, правда не намного, работает следующая:
insert into tab1(ID, ...) values (ID.NextVal, ...) returning ID into :ID;
insert into tab2(Parent_ID, ...) values (:ID, ...);

Re SergSuper
Я никакой знаток MSSQL, но с общетеоретических позиций Ваше решение потенциальная точка конфликта за разделяемые ресурсы в БД со стороны многих конкурирующих пользовательских сессий, как на уровне lock"ов записи таблицы GEN_ID в БД, так и на уровне доступа к соответствующему блоку данных в кеше. Предлагается оперировать _диапазонами_ ID, то есть каждая сессия запрашивает в таблице за один раз ни одно значение, а целую серию. В Оракл это достаточно просто реализовать через пакет, как сделать в MSSQL не знаю.
Есть у меня вопрос - прочитал в умной книжке Тома Кайта о локе сервером MSSQL изменяемой в одной сессии записи для чтения другой сессией. Так ли это на практике ?


 
SergSuper   (2003-11-25 18:01) [15]

2 hCat
Если вызывать процедуру вне транзакции то блокировка будет только на момент работы процедуры, что не очень долго. Хотя согласен не всегда это возможно.
Но во-первых под каждый конкретный случай можно придумать что-то конкретное.
Во-вторых я лично такие процедуры не писал и мне вполне хватало identity.

Что такое пакет в Оракле - не знаю. Про лок - не понял вопрос.


 
Delirium   (2003-11-25 18:08) [16]

Для тех кому 16 байт на идентификатор кажется расточительно, можно элементарно получить хеш
select Binary_CheckSum(NewID())


 
Delirium   (2003-11-25 18:24) [17]

> "Основной недостаток guid - их трудно прочитать, записать, продиктовать по телефону и т.д." - совершенно верно, тольно не недостаток, а преимущество которое отучает использовать идентификаторы не по назначению! По телефону надо диктовать номер документа, но уж точно не идентификатор, а если при проектировании базы данных не заложили разницу между тем, что печатается на бумаге и тем, по чему строятся кластерные индексы, то тогда не долго до того, что в качестве индентификаторов будем использовать символьные поля - какие-нибудь названия материалов!


 
Shirson   (2003-11-26 11:53) [18]

>KSergey © (25.11.03 12:35) [13]
>Все, но не забывайте уточнять, что это только начиная с MS SQL 2000

Глубина погружения в старые версии по совместимости не указана :)

>Видимо, вы начали с MS SQL 2000
Потому и не в курсе. Ранее было только @@IDENTITY

Я начинал с 6.5 :)
И учитывал бы это в разговоре с амерами или еврожо.., где версии не обновляют до последнего, экономя деньги.
Но никак бы не стал зацикливаться на проблеме покупки новой версии, на просторах СНГ, которая у махровых стоит порядка 2-3 у.е., а не 20000-30000 у.е. :)


 
hCat   (2003-11-26 13:40) [19]

Re SergSuper

> Если вызывать процедуру вне транзакции то блокировка будет
> только на момент работы процедуры, что не очень долго. Хотя
> согласен не всегда это возможно.

На низкой нагрузке Вы это вряд ли заметите, мое замечание относится скорее к возможностям масштабирования решения даже с вынесенной из транзакции процедуры.


> Что такое пакет в Оракле - не знаю

Процедурный код объединенный с данными, хранящийся на сервере. Некий аналог объекта, но по сравнению например с Delphi весьма убогий.


> Про лок - не понял вопрос

Суть в следующем: допустим имеем таблицу Т и две сессии С1 и С2, если из С2 изменить одну запись и не делать commit/rollback, а в С1 сделать select то С1 будет ждать завершения транзакции сессии С2. Так ли это ? Дело в том, что в Оракл запись не блокирует чтение, с некотрыми оговорками.


 
SergSuper   (2003-11-26 14:51) [20]


> На низкой нагрузке Вы это вряд ли заметите, мое замечание
> относится скорее к возможностям масштабирования решения
> даже с вынесенной из транзакции процедуры.

Ну если дополнительный апдейт обновление одной строки маленькой таблицы как-то влияет на масштабируемость... Мне кажется несерьёзно. Опять же повторю - вполне можно обходиться и без таких генераторов.

> пакет в Оракле

А сохранённая процедура - не тоже самое? Наверное без примера не понять.

про блокировки
Тут в MS SQL конечно похуже. Есть 2 варианта: или С1 будет ждать, или С1 будет читать незакомиченные текущие данные(в зависимости от установленного уровня изоляции). В следущей версии(в Юконе) обещают сделать еще и вариант как в Оракле - читать последние закомиченные данные. Хотя если мы читаем данные с целью их же потом обновить - тут в любом случае нужна блокировка.


 
Val   (2003-11-26 14:57) [21]

>hCat (26.11.03 13:40) [19]
>SergSuper (26.11.03 14:51) [20]
О пакетах. Мне кажется, hCat немного неверно сравнивает пакет с объектом. Я бы сказал, что он более похож на паскалевский модуль, который содержит, как известно, раздел объявления и раздел реализации, с соответствующей доступностью/недоступностью извне к процедурам/функциям и данным.


 
hCat   (2003-11-27 12:52) [22]

2 Val
Согласен разницы с юнитом гораздо меньше, чем с объектом, но мне лично проще думать при построении (реализации) алгоритма в терминах объектов (классов) пусть убогих, чем юнитов.

2 SergSuper

> Ну если дополнительный апдейт обновление одной строки маленькой
> таблицы как-то влияет на масштабируемость... Мне кажется
> несерьёзно.

Что ж давайте порассуждаем насколько влияет такая процедура на массштабируемость приложения.
Пусть целевой инсерт отрабатывает за время Т1, а процедура за Т2. Очевидно, что влияние нашей процедуры будет тем меньше, чем больше время Т1, по сравнению с Т2. Говоря грубо на фоне 1000 ед для Т1 10 ед для Т2 погоды не делают. При параллельной работе и использовании процедуры для получения ID, она (процедура) станет тем участком кода, который будет выстраивать все задачи на добавление последовательно (мы локируем запись таблицы). При этом следует учитывать, что время Т2 будет расти не линейно при увеличении кол-ва сессий из-за накладных расходов по управлению служебными структурами самого сервера, многопотоковой работе с общей памятью в частности - доступе к одной строке кеша многими потоками. Предположим, что вся совокупность реального времени для исполнения процедуры T2rt, а в распоряжении сервера всегда есть только одна секунда реального времени. Соответсвенно пропускная способность сервера по добавлению строк в таблицу (целевая задача) будет 1/(T2rt*fn(SessionNr)), где fn возвращает коэффициент замедления в зависимости от кол-ва сессий и меньше единицы этот коэффециент быть не может. Здесь мы полностью исключаем затраты непосредственно по добавлению строки в целевую таблицу. Однако главная неприятность массштабирования по кол-ву сессий заключается в особенностях fn - эта функциия достаточно плавно растет до некотрого кол-ва сессий, зато потом очень быстро возрастает до бесконечности. Особенности этой функ я принимаю как данность, хотя могу поискать ссылки на литературу. Опять же ее характер хорошо подтверждается практикой.

Резюме: проблемы с массштабированием можно получить как на коротких целевых транзакциях с малым кол-вом сессий, так и на длинных целевых транзакциях с большим кол-вом сессий. А на коротких целевых транзакциях с большим кол-вом сессий проблемы получаются очень быстро.

ЗЫ "В моих словах нет ни капли контрреволюции, в них только здравый смысл и жизенная опытность" М.Булгаков. "Собачье сердце"



Страницы: 1 вся ветка

Форум: "Базы";
Текущий архив: 2003.12.19;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.009 c
3-61905
Саша
2003-11-27 13:03
2003.12.19
Не находится libmysql.dll (MySQL + DbExpress)


1-62008
Multy
2003-12-06 18:31
2003.12.19
Сравнение кусков текста


1-62049
DikobraZ
2003-12-04 22:34
2003.12.19
Какие компоненты используют в uses: Compress, CompressZli...


3-61902
Murad
2003-11-27 12:03
2003.12.19
Backup в MSSql


14-62248
Fredericco
2003-11-15 21:54
2003.12.19
Отчет о разведке NYMMP 2003.





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский