Можно ли создавать подробные сообщения об ошибках из сложных запросов к базе данных? - PullRequest
4 голосов
/ 30 октября 2010

Позвольте мне проиллюстрировать этот вопрос на упрощенном примере. Предположим, я строю проект с использованием python с реляционной базой данных PostgreSQL. В моей базе данных у меня есть две таблицы "parent" и "child", которые связаны с N по M через таблицу "parent_child". Я хочу иметь возможность получать некоторые данные о конкретном дочернем элементе, принадлежащем конкретному родителю, безопасным способом, что позволяет мне сделать следующий запрос (X, Y и Z - литералы, предоставленные пользователем):

SELECT child.age FROM parent, parent_child, child 
WHERE child.id = parent_child.child_id AND parent_child.id = X 
AND parent_child.parent_id = parent.id AND parent.id = Y 
AND parent.password = Z; 

Скажем, пользователь приходит и вводит неправильное значение для X, Y или Z, запрос вернет пустой набор, который может быть обнаружен, и передаст пользователю сообщение об ошибке. Проблема, конечно, в том, что я не могу определить, какое значение вызывает проблемы, и, следовательно, не могу предоставить пользователю конкретную информацию о том, что он неправильно ввел?

Самое простое решение - разбить запрос на несколько частей. Сначала убедитесь, что parent.id существует.

SELECT parent.id FROM parent WHERE parent.id = Y;

Во-вторых, проверка правильности пароля.

SELECT parent.id FROM parent WHERE parent.id = Y and parent.password = Z;

В-третьих, проверка, существует ли ребенок.

SELECT child.id FROM child WHERE child.id = X;

В-четвертых, проверка того, что ребенок принадлежит родителю, и возвращение необходимой нам информации.

SELECT child.age FROM child, parent_child WHERE parent_child.child_id = child.id AND parent_child.parent_id = Y AND parent_child.child_id = X;

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

Ответы [ 3 ]

3 голосов
/ 30 октября 2010
SELECT  p.id, p2.z AS pw, pc.parent_id, CASE p2.z WHEN p.pw THEN c.age END AS age
FROM    (VALUES (1)) AS p1(y)
LEFT JOIN
        parent p
ON      p.id = p1.y
LEFT JOIN
        (VALUES ('pw1')) AS p2(z)
ON      p2.z = p.pw
CROSS JOIN
        (VALUES(1)) AS p3(x)
LEFT JOIN
        child c
ON      c.id = p3.x
LEFT JOIN
        parent_child pc
ON      pc.parent_id = p.id
        AND pc.child_id = c.id

NULLs в соответствующих столбцах будет означать, что соответствующие условия не выполнены.

1 голос
/ 30 октября 2010

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

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

0 голосов
/ 31 октября 2010

Эти четыре запроса позволят нам проверить конкретные сведения о предоставленной пользователем информации и сообщить о конкретных проблемах по мере их возникновения.

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

Очевидно, что в четырех запросах возникает много дополнительных затрат на один запрос

Я не понимаю вашу арифметику. Скажем, каждыйзапрос к таблице по PK стоит 50 единиц ресурса, если его нет в кэше данных, и 2 единицы, если он есть.Предполагая, что PostgreSQL имеет кэш данных и многопоточный движок, а ваш сегмент кода представляет собой непрерывную последовательность (хранимый процесс или нет):

  • первый оператор = 50
  • второй оператор(поскольку страница находится в кеше) = 2
  • третья инструкция = 50
  • четвертая инструкция (так как родитель и потомок находятся в кеше) = 2 + 2 + 50
  • равно 156 единицам

  • более важно, в случае ошибки стоимость (в зависимости от того, где находится ошибка) составляет 50 или 52 или 102 единицы

  • , тогда как отдельный четвертый оператор стоит 150 единиц

Я считаю четыре запроса менее читаемыми, чем один.

Putмежду пробелами и комментариями, если вам нужно улучшить читаемость.(Ваш код труден для прочтения в любом случае; я бы отформатировал его.)

Один запрос и подробные сообщения об ошибках?

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

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

...