Будет ли ключ в SQL еще оставаться ключом в представлении - PullRequest
6 голосов
/ 20 марта 2011

Допустим, у меня есть таблица mysql под названием FISH с полями A, B и C.

Я запускаю SELECT * FROM FISH.Это дает мне представление обо всех областях.Итак, если A был ключом в исходной таблице, это также ключ в представлении?То есть, если у меня есть таблица FISH2, и я запустил

 SELECT * FROM (SELECT * FROM FISH) D, (SELECT * FROM FISH2) E WHERE D.A = E.A

Будут ли соответствующие поля по-прежнему ключами?

Теперь давайте сделаем еще один шаг.Если я выполню

SELECT * FROM (SELECT CONCAT(A,B) AS DUCK, C FROM FISH) D, (SELECT CONCAT(A,B) AS DUCK2, C FROM FISH2) E WHERE D.DUCK = E.DUCK2

Если A и B были ключами в исходных таблицах, будет ли их конкатенация также ключом?

Спасибо :))

Ответы [ 3 ]

2 голосов
/ 21 марта 2011

Если A является ключом в fish, то любая проекция только на рыбу создаст набор результатов, где А все еще уникален.

Соединение между таблицей fish и любой таблицей с соотношением 1: 1 (например, fish_type) даст набор результатов, в котором A уникален.

Соединение с другой таблицей, имеющей отношение 1: M или M: M от fish (например, fish_beits), НЕ даст результата, в котором A уникален, если только вы не предоставите предикат фильтра на «другой» стороне (такой как bait='Dynamite').

SELECT * FROM (SELECT * FROM FISH) D, (SELECT * FROM FISH2) E WHERE D.A = E.A

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

select *
  from fish
  join fish2 on(fish.a = fish2.a)

Является ли A все еще уникальным в наборе результатов, зависит от ключа fish2 и их отношения (см. Выше).

Конкатенация не сохраняет уникальность. Рассмотрим следующий случай:

concat("10", "10") => "1010"
concat("101", "0") => "1010"

Следовательно, ваш последний запрос ...

SELECT * 
  FROM (SELECT CONCAT(A,B) AS DUCK, C FROM FISH) D
      ,(SELECT CONCAT(A,B) AS DUCK2, C FROM FISH2) E 
 WHERE D.DUCK = E.DUCK2

... не будет (обязательно) давать тот же результат, что и

select * 
  from fish 
  join fish2 on(
       fish.a = fish2.a
   and fish.b = fish2.b
  )

Я написал обязательно , потому что коллизии зависят от фактических значений. Некоторое время назад я выискивал ошибку, в которой именно эта причина и была. Код работал несколько лет, пока ошибка не проявилась.

0 голосов
/ 20 марта 2011

Для шага 1 представьте представление как подзапрос, содержащий все, что содержится в предложении AS при выполнении CREATE VIEW.

Например, если представление v создается как SELECT a, b, c FROM t, то при выполнении ...

SELECT * FROM v WHERE a = some_value

... это концептуально трактуется как ...

SELECT * FROM (SELECT a, b, c FROM t) WHERE a = some_value

Любая база данных с приличным оптимизатором заметит, что столбец a передается прямо в результаты и что он может воспользоваться индексированием в t (если есть), перемещая его в подзапрос:

SELECT * FROM (SELECT a, b, c FROM t WHERE a = some_value)

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

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

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

0 голосов
/ 20 марта 2011

Если под «ключом» вы подразумеваете «уникальный», то да, кортежи декартового произведения над уникальными значениями будут уникальными. (Это можно доказать с помощью reductio ad absurdum.)

...