Вопросы на собеседовании
PHP
C++ (ООП)
Базы данных
.NET
Некоторые распространенные вопросы на собеседовании по базам данных:
Что такое внешний ключ?
Что такое нормализация БД?
Что такое денормализация БД? Для чего она нужна?
Что такое кластерный и некластерный индекс?
Какие типы соединений (join) таблиц существуют? В чем их разница?
Что такое SQL курсор?
Опишите шаги по созданию и использованию курсора?
Что такое транзакция?
Что такое блокировка?
Что такое deadlock?
Что такое триггер? (Какие типы триггеров вы знаете?)
В чем разница между WHERE и HAVING?
Что такое подзапрос (sub-query)?
Оставить комментарий
Что такое первичный ключ?
В теории реляционных баз данных логическая группировка элементов данных называется «отношением», а определенный экземпляр отношения - «кортежем». Так вот первичный ключ — это множество атрибутов отношения, которое уникально определяет кортеж этого отношения.
На практике первичный ключ означает определенный набор столбцов таблицы, который уникально идентифицирует каждую строку. Первичный ключ может состоять как из одного столбца, так и из нескольких.
Например, рассмотрим таблицу заказов, состоящую из столбцов:
- order_id (уникальный номер заказа — первичный ключ)
- order_date (дата совершения заказа)
- order_customer (покупатель, сделавший покупку)
- order_sum (сумма заказа).
В этой таблице столбец order_id является первичным ключом и уникально определяет каждую строку таблицы, т.е. заказ.
Что такое внешний ключ?
Когда поле таблицы ссылается на другое поле в другой таблице, оно называется внешним ключом. Поле, на которое он ссылается, является первичным ключом.
Например, в таблице заказов, очевидно, должно быть поле order_customer, которое определяет покупателя сделавшего покупку. Мы могли бы в это поле записывать просто ФИО покупателя. Но как быть, если нам нужно выбрать все заказы, сделанные конкретным покупателем? Велика вероятность, что в таблице могут находится люди, у которых полностью совпадает ФИО.
Во избежание подобных проблем (примеров можно придумать массу) в поле order_customer необходимо хранить внешний ключ, который будет ссылаться на первичный ключ в таблице customers (покупатели).
Например, в таблице заказов будет строка, где в поле order_customer содержится внешний ключ — 3246. Далее в таблице customers необходимо отыскать строку с первичным ключом, равным 3246, в этой строке и будут содержаться все данные покупателя, включая и ФИО.
Что такое нормализация БД?
Процесс приведения базы данных к виду, в котором она будет соответствовать правилам нормальных форм, называется нормализацией базы данных.
Нормализация базы данных сводит к минимуму количество избыточной информации. Ее целью является сохранять данные только один раз, но в нужном месте.
Нормализованная база данных исключает дублирование и многократное обслуживание данных, а также появление проблем с целостностью данных, возникающих при повторном вводе одинаковых данных.
Первоначально доктором Эдгаром Коддом были определены только 3 нормальные формы. Дальнейшая разработка реляционной теории привела к появлению еще нескольких форм и на данный момент их насчитывается 6.
На практике соответствие базы данных правилам 3-ей нормальной формы вполне достаточно.
Что такое денормализация БД? Для чего она нужна?
Денормализация — это процесс осознанного приведения базы данных к виду, в котором она не будет соответствовать правилам нормализации. Обычно это необходимо для повышения производительности и скорости извлечения данных, за счет увеличения избыточности данных.
Если приложению необходимо часто выполнять выборки, которые занимают слишком много времени (например, объединение данных из множества таблиц), то следует рассмотреть возможность проведения денормализации.
Возможное решение следующее: вынести результаты выборки в отдельную таблицу. Это позволит увеличить скорость выполнения запросов, но также означает появление необходимости в постоянном обслуживании этой новой таблицы.
Прежде чем приступать к денормализации, необходимо убедится, что ожидаемые результаты оправдывают издержки, с которыми придется столкнуться.
Что такое кластерный и некластерный индекс?
Индексы делятся на 2 вида — кластерный и некластерный.
Обычно СУБД хранит строки в том порядке, в котором они добавляются в таблицу.
Кластерный индекс предлагает собой способ хранения строк таблицы так, что их действительное хранение связано с логическими значениями в некоторых столбцах. В кластере могут содержаться либо строки из одной таблицы, либо связанные между собой строки из нескольких таблиц.
Некластерный индекс хранит указатели на строки в таблице. Такой способ хранения подразумевает после обращения к индексу обращение к самой таблице для получения строк.
Наиболее часто используемые типы индексов:- B-деревья
- Хеши
- R-деревья
- Полнотекстовые
В отличие от некластерного индекса, таблица может иметь только один кластерный индекс.
Какие типы соединений (join) таблиц существуют? В чем их разница?
- INNER JOIN
- FULL OUTER JOIN
- LEFT OUTER JOIN
- RIGHT OUTER JOIN
- CROSS JOIN
Опишем каждый тип соединений на примере запросов. Рассмотрим 2 таблицы A и B:
A:ID | NAME |
1 | Вася |
2 | Петя |
3 | Федя |
4 | Маша |
B:
ID | NAME |
1 | Иван |
2 | Вася |
3 | Лена |
4 | Федя |
Посмотрим на результаты следующих запросов:
SELECT * FROM A INNER JOIN B ON A.NAME = B.NAMEID | NAME | ID | NAME |
1 | Вася | 2 | Вася |
3 | Федя | 4 | Федя |
SELECT * FROM A FULL OUTER JOIN B ON A.NAME = B.NAME
ID | NAME | ID | NAME |
1 | Вася | 2 | Вася |
2 | Петя | null | null |
3 | Федя | 4 | Федя |
4 | Маша | null | null |
null | null | 1 | Иван |
null | null | 3 | Лена |
SELECT * FROM A LEFT OUTER JOIN B ON A.NAME = B.NAME
ID | NAME | ID | NAME |
1 | Вася | 2 | Вася |
2 | Петя | null | null |
3 | Федя | 4 | Федя |
4 | Маша | null | null |
SELECT * FROM A RIGHT OUTER JOIN B ON A.NAME = B.NAME
ID | NAME | ID | NAME |
3 | Федя | 4 | Федя |
null | nul | 3 | Лена |
1 | Вася | 2 | Вася |
null | null | 1 | Ivan |
SELECT * FROM A CROSS JOIN B
4 | Masha | 4 | Fedya |
3 | Fedya | 4 | Fedya |
2 | Petya | 4 | Fedya |
1 | Vasya | 4 | Fedya |
4 | Masha | 3 | Lena |
3 | Fedya | 3 | Lena |
2 | Petya | 3 | Lena |
1 | Vasya | 3 | Lena |
4 | Masha | 2 | Vasya |
3 | Fedya | 2 | Vasya |
2 | Petya | 2 | Vasya |
1 | Vasya | 2 | Vasya |
4 | Masha | 1 | Ivan |
3 | Fedya | 1 | Ivan |
2 | Petya | 1 | Ivan |
1 | Vasya | 1 | Ivan |
CROSS JOIN является полным декартовым произведением, т.е. возвращает все возможные сочетания записей таблиц A и B. В стандартном SQL CROSS JOIN выполняется без условия ON, однако, например, в MySQL этого ограничения нет и CROSS JOIN является аналогом INNER JOIN.
Что такое SQL курсор?
Иногда бывает нужно в результирующем наборе SQL-запроса обрабатывать строки по одной. Для этого обычно используются циклы и объект, называемый курсором.
SQL курсор можно представить как указатель в результирующем наборе. Его можно перемещать, обрабатывая каждую строку, пока не закончится результирующий набор.
Опишите шаги по созданию и использованию курсора?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | CURSOR cselectitem IS SELECT id, name FROM items; /* Объявляем курсор, привязывая к нему SQL — запрос. */ BEGIN OPEN cselectitem; /* Далее перед использованием курсор необходимо открыть */ LOOP FETCH cselectitem INTO item_id, item_name; /* В цикле вытаскиваем каждую строку, используя конструкцию FETCH, и значения полей выборки записываем в переменные, которые должны быть заранее объявлены */ EXIT WHEN cselectitem%NOTFOUND; /* Выходим из цикла, когда достигнут конец результирующего набора */ END LOOP; CLOSE cselectitem; /* Закрываем курсор */ END |
Что такое транзакция?
По определению, транзакция — это логическая единица работы.
Транзакция предполагает, что все, входящие в нее SQL-запросы будут обязательно выполнены, причем одновременно.
Начать транзакцию можно при помощи команды BEGIN TRANSACTION. Завершить можно либо сохранив изменения в базе данных при помощи команды COMMIT, либо удалив все сделанные транзакцией изменения командой ROLLBACK
Приведем пример транзакции, которая снимает деньги с одного пользовательского счета и переводит их на другой:1 2 3 4 5 6 | BEGIN TRANSACTION UPDATE user_account SET balance=balance-100 WHERE account_id=1 /* Снимаем деньги со счета, ID которого равен 1 */ UPDATE user_account SET balance=balance+100 WHERE account_id=2 /* И переводим эти деньги на счет, ID которого равен 2 */ COMMIT |
Понятно какие-бы проблемы могли бы возникнуть, если бы одна часть этой транзакции была бы выполнена успешно, а другая нет. Однако использование транзакций не допускает подобных ситуаций.
При работе с транзакциями возможны 2 варианта:- результаты выполнения всех запросов, входящих в транзакцию, будут применены к базе данных
- все внесенные изменения в базу данных будут отменены (откатаны).
Пока результаты выполнения запросов, входящих в транзакцию не будет применены к базе данных при помощи оператора COMMIT, они остаются невидимы для других пользователей базы данных.
Что такое блокировка?
- Разделяемая блокировка
Когда пользователь считывает данные, его совершенно не волнует кто эти данные считывает еще.
При подобных операциях на данные накладывается разделяемая блокировка, которая говорит о том, что любая транзакция может выполнять эту же операцию с данными, т.к. она не изменяет их и не сможет привести ни к каким побочным эффектам. - Монопольная блокировка
В случае, если выполняемая операция изменяет данные, на них накладывается монопольная блокировка, которая позволяет изменять данные только одному пользователю.
СУБД не может устанавливать монопольную блокировку на данные, на которые уже установлена разделяемая блокировка. Такое ограничение имеет смысл как для пользователя, который записывает данные, так и для пользователя, который их считывает.
Что такое deadlock?
Взаимная блокировка (или deadlock) — это ситуация, при которой возник конфликт между несколькими операциями записи.
Рассмотрим пример:Операция 1 | Операция 2 |
Необходимо изменить данные A и B | |
Происходит изменение данных A | |
Происходит изменение данных B | |
Ожидание снятия блокировки с данных A | |
Ожидание снятия блокировки с данных B |
В описанном примере обе операции могут снять блокировку с данных только после полного завершения своей работы. Но для завершения работы операции 1 нужно снятие блокировки с данных B, а для операции 2 снятие блокировки с данных A. Обе операции вступают в бесконечное ожидание снятия блокировки с данных.
Обойти эту проблему никак нельзя, поскольку СУБД не может разрешить двум операциям вносить изменения в один и тот же фрагмент данных одновременно, не потеряв при этом весь контроль над целостностью данных.
Поскольку исключить потенциальную возможность возникновения взаимных блокировок нельзя, лучшее решение — это уменьшить промежуток времени, во время которого взаимная блокировка может произойти.
Другими словами команда COMMIT должна выполняться сразу, как только операция записи станет возможна, для сокращения времени, в течение которого данные заблокированы.
Что такое триггер? (Какие типы триггеров вы знаете?)
Триггеры — это части кода, запускаемые автоматически и основанные на каком-либо действии или событии в таблице базы данных.
Триггеры могут применять в таблице во время выполнения операторов INSERT, UPDATE или DELETE, а затем работать или перед, или после этих действий.
Некоторые СУБД также позволяют работать триггерам на уровне оператора или на уровне каждой строки данных во время ее изменения.
В чем разница между WHERE и HAVING?
Конструкцию HAVING можно использовать только при наличии конструкции GROUP BY. Она действует по отношению к результатам конструкции GROUP BY аналогично тому, как конструкция WHERE отсеивает строки, возвращаемые оператором SELECT, в соответствии с указанным условием.
Что такое подзапрос (sub-query)?
Подзапрос — это запрос, вложенный в другой запрос.
Несколько примеров подзапросов:1 2 3 4 | SELECT * FROM tableA WHERE id IN (SELECT id FROM tableB) SELECT * FROM tableA WHERE id > (SELECT AVG(id) FROM tableA) SELECT tA.* FROM (SELECT * FROM tableA WHERE col IS NOT NULL) tA, tableB tB WHERE tA.id=tB.id |
|
0 | Tweet | Нравится |
|
На этот раздел с вопросами оставлено 9 комментариев
-
Даниил
26 Апрель 2011 22:39:46 (ссылка)>Конструкцию HAVING можно использовать только при наличии конструкции >GROUP BY.
А как насчет работы с расчитанными полями? Например такой тип запроса:
SELECT
cat,
(SELECT count(*) FROM category t2 WHERE t2.cat=t1.cat AND t2.date>t1.date ) c
FROM
category t1
HAVING
c -
Александр
22 Июнь 2011 17:28:21 (ссылка)>Конструкцию HAVING можно использовать только при наличии конструкции GROUP BY.
HAVING (Transact-SQL)
Определяет условие поиска для группы или статистического выражения. Предложение HAVING можно использовать только в инструкции SELECT. Предложение HAVING обычно используется в предложении GROUP BY. Когда GROUP BY не используется, предложение HAVING работает так же, как и предложение WHERE. -
-
pereiiro
30 Август 2012 12:00:49 (ссылка)что мешает выполнить такой запрос?
select count(*)
from sys.databases
having count(*)> 1 -
llv
13 Октябрь 2013 14:46:20 (ссылка)"В чем различие между выражениями HAVING и WHERE"
WHERE - это ограничивающее выражение. Оно выполняется до того, как будет получен результат операции.
HAVING - фильтрующее выражение. Оно применяется к результату операции и выполняется уже после того как этот результат будет получен, в отличии от where.
Выражения WHERE используются вместе с операциями SELECT, UPDATE, DELETE, в то время как HAVING только с SELECT и предложением GROUP BY -
-
-
Сергей
01 Апрель 2016 16:59:18 (ссылка)Странные тут вопросы, составленные из коротких основ, по индексам я бы вообще страшивал, в чем +- кластерного, что такое куча, куда и почему будит быстрей будит производиться вставка в кластерную таблицу или heap, сто такое ограничители (constraint) для чего нужны, да и индексов нынче по боле будит
-
Эльхан
03 Ноябрь 2016 10:30:53 (ссылка)Следует уточнить, что having используется c агрегатными функциями для фитльтрации, where в этом случае не поможет.