Что должно быть возвращено при вставке в SQL? - PullRequest
1 голос
/ 27 января 2010

Несколько месяцев назад я начал использовать генератор сценариев CRUD для SQL Server. Оператор вставки по умолчанию, который генерирует этот генератор, SELECT выбирает вставленную строку в конце хранимой процедуры. То же самое относится и к ОБНОВЛЕНИЮ.

Предыдущий способ (и единственный другой способ, который я видел в Интернете) - просто вернуть вновь вставленный идентификатор обратно в бизнес-объект, а затем заставить бизнес-объект обновить идентификатор записи.

Наличие дополнительного SELECT, очевидно, является дополнительным вызовом базы данных, и в приложение возвращается больше данных. Однако это обеспечивает дополнительную гибкость хранимой процедуры и позволяет приложению отображать фактические данные в таблице.

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

Мне интересно, что люди считают лучшим способом сделать это, и я не имею в виду реализацию того или иного метода. Что лучше, вернуть только идентификатор или вернуть весь ряд?

Ответы [ 6 ]

3 голосов
/ 27 января 2010

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

1 голос
/ 27 января 2010

Исходя из моего предыдущего опыта, моя реакция коленного рефлекса состоит в том, чтобы просто вернуть только что сгенерированное значение личности. Все остальное, что приложение вставляет, оно уже знает - имена, доллары, что угодно. Но несколько минут размышления и прочтения предыдущих 6 (хм, сделайте это 5) ответов приводят к ряду ситуаций «все зависит»:

  • На самом базовом уровне то, что вы вставили, - это то, что вы получите - вы передаете значения, они записываются в строку в таблице, и все готово.

  • Немного сложнее, чем когда в операторе вставки назначаются простые значения по умолчанию. Столбцы «DateCreated», которые по умолчанию соответствуют текущему времени, или «CreatedBy», которые по умолчанию соответствуют текущему имени входа SQL, являются ярким примером. Я бы добавил сюда столбцы идентификаторов, поскольку не каждая таблица будет (или должна) содержать их. Эти значения генерируются базой данных при вставке таблицы, поэтому вызывающее приложение не может знать, что это такое. (Неизвестно, что часы веб-сервера не синхронизируются с часами сервера базы данных. Забавные времена ...) Если приложению нужно знать только что сгенерированные значения, то да, вам нужно будет передать их обратно.

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

С учетом вышесказанного мне кажется, что основная проблема, лежащая в основе вашего решения, заключается в следующем: насколько вы контролируете / понимаете базу данных? Вы говорите, что используете инструмент для автоматической генерации ваших процедур CRUD. Хорошо, это означает, что у вас нет какой-либо сложной обработки внутри них, вы просто берете данные и загружаете их. Следующий вопрос: присутствуют ли триггеры (любого рода), которые могут изменять данные в том виде, в котором они находятся записано в таблицы? Распространите это на: вы знаете , существуют ли такие триггеры? Если они там и имеют значение, планируйте соответственно; если вы этого не знаете или не можете знать, вам, возможно, придется «проследить» за вкладышем, чтобы увидеть, произошли ли изменения. Наконец: заботится ли приложение? Нужно ли информировать его о результатах только что запрошенного действия вставки, и если да, то сколько ему нужно знать? (Новое значение идентификатора, дата и время добавления, независимо от того, изменилось ли что-либо Имя с «Виджет» на «Виджет_201001270901».)

Если у вас есть полное понимание и контроль над системой, которую вы строите, я бы добавил только столько, сколько вам нужно, поскольку дополнительный код, который не выполняет никаких полезных функций, влияет на производительность и ремонтопригодность. С другой стороны, если бы я писал инструмент для использования другими, я бы попытался создать что-то, что сделало бы все (чтобы увеличить свою долю на рынке). И если вы создаете код, в котором вы на самом деле не знаете, как и почему он будет использоваться (цель приложения) или с чем он, в свою очередь, будет работать (проектирование базы данных), тогда, я думаю, вы должны быть параноиком и попробуйте программировать для всего. (Я настоятельно рекомендую не делать этого. Избегайте делать только то, что нужно сделать.)

1 голос
/ 27 января 2010

Оператор выбора будет иметь какое-то преимущество только в том случае, если данные генерируются в процедуре. В противном случае введенные вами данные, как правило, вам уже доступны, поэтому нет смысла выбирать и возвращать их снова, ИМХО. если это для идентификатора, то вы можете иметь его с SCOPE_IDENTITY (), который вернет последнее значение идентификатора, созданное в текущем сеансе для вставки.

0 голосов
/ 27 января 2010

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

Если вы генерируете код, вы можете сгенерировать два процесса (один, который вызывает другой, возможно) или параметризовать один процесс, чтобы определить, возвращать ли его по проводам или нет. Я сомневаюсь, что издержки БД значительны (однострочный, должен иметь поиск по PK), но данные по проводам от БД к клиенту могут быть значительными, когда все сложено, и если их просто отбрасывают в 99% случаев, я увидеть мало значения. Разумеется, наличие SP, который возвращает разные вещи с разными параметрами, является потенциальной проблемой для клиентов.

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

Помещение ЛЮБОЙ логики в базу данных - это, как правило, тщательно продуманный компромисс, который начинается с минимально инвазивных и максимально полезных вещей, таких как ограничения, уникальные ограничения, ссылочная целостность и т. Д., И переходит к более инвазивным и минимально полезным инструментам, таким как триггеры. .

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

0 голосов
/ 27 января 2010

Довольно часто база данных имеет свойство, которое дает вам идентификатор последнего вставленного элемента без необходимости дополнительного выбора. Например, MS SQL Server имеет свойство @@ Identity (см. здесь ). Вы можете передать это обратно своему приложению в качестве выходного параметра вашей хранимой процедуры и использовать его для обновления ваших данных новым идентификатором. MySQL имеет нечто подобное.

0 голосов
/ 27 января 2010
INSERT
INTO    mytable (col1, col2)
OUTPUT  INSERTED.*
VALUES  ('value1', 'value2')

В этом пункте для возврата всей строки не требуется дополнительная SELECT, а в отношении производительности то же самое, что и возвращение только id.

«Что лучше» полностью зависит от потребностей вашего приложения. Если вам нужна вся строка, верните всю строку, если вам нужна только id, верните только id.

Вы можете добавить дополнительный параметр в свой бизнес-объект, который может активировать эту опцию и возвращать всю строку, только если объекту это необходимо:

IF @return_whole_row = 1
        INSERT
        INTO    mytable (col1, col2)
        OUTPUT  INSERTED.*
        VALUES  ('value1', 'value2')
ELSE
        INSERT
        INTO    mytable (col1, col2)
        OUTPUT  INSERTED.id
        VALUES  ('value1', 'value2')
FI
...