Схема базы данных MySQL для двух реляционных таблиц - PullRequest
2 голосов
/ 22 марта 2019

Я пытаюсь найти наиболее эффективную схему базы данных для конкретной структуры данных.Существует два основных объекта: Курсы и Темы . Курс - это коллекция Тем .A Тема имеет такие поля, как Видео , Ресурсы и Общее время видео .

Визуально представляет эту структуру данных:

- Course
|_ ID: 12345
|_ Themes: [A, B] (an array of UIDs)

- Theme A
  |_ Courses: [12345,67890] (an array of UIDs)
  |_ Videos: [1,2,3,4,5,7] (an array of UIDs)
  |_ Resources: [10,11,12] (an array of UIDs)
  |_ Video Total Time: 10000 (probably stored as seconds as tinyint field)
- Theme B
  |_ Courses: [12345,98765] (an array of UIDs)
  |_ Videos: [5,6,7,8] (an array of UIDs)
  |_ Resources: [12,13,14] (an array of UIDs)
  |_ Video Total Time: 20000 (probably stored as seconds as tinyint field)

Я пытаюсь добиться схемы базы данных для двух таблиц, одной для курсов и одной для тем .Идея состоит в том, чтобы иметь запрос MySQL, который получает Course и группировать все поля из Themes .Другими словами, когда я получу результат запроса MySQL (используя PHP), я получу массив или объект, подобный этому:

Array(
  'ID' => 12345
  'themes' => [A,B]
  'videos' => [1,2,3,4,5,6,7,8]
  'resources' => [10,11,12,13,14]
  'video_total_time' => 30000
)

Итак, дело в том, что это две реляционные базы данных.Когда я отправляю запрос в БД с запросом данных из видео, мне нужно извлечь данные из всех тем и объединить их вместе.

Поскольку я не эксперт по SQL / MySQL, япытаясь немного узнать об этом, пока я пытаюсь понять:

1) Какова лучшая схема базы данных для этих двух объектов?Курсы и Темы?Особенно задумываясь о производительности

2) Могу ли я получить окончательные данные, используя SQL?Или я должен извлечь некоторые данные из базы данных, а затем проанализировать данные с помощью PHP?Что обычно быстрее?

3) Как лучше всего хранить массив UID?Как строка?Или есть лучший способ сохранить его?

Основная цель - производительность.У меня есть данные такого типа в другой схеме базы данных, объединенные с тысячами других типов данных (базы данных WP, таблицы wp_posts / wp_postmeta), но сейчас получить информацию, которая мне нужна, очень медленно.

Любаясоветы и предложения приветствуются!


Редактировать: Решено!

Было непросто решить, какой ответ лучше всего соответствует моим потребностям, потому что ответы @ TimMorton и @ PaulSpiegel ведут насна тот же путь, но с немного другими подходами.Ответ Тима великолепен, чтобы понять, как правильно проектировать схемы базы данных, принимая во внимание отношения «многие ко многим» и как организовывать свои запросы.Но поскольку основное внимание в этом вопросе уделяется повышению производительности, ответ Пола более сфокусирован на этом с конкретными сведениями о первичных ключах и индексах (которые имеют основополагающее значение для повышения производительности запросов).

В любом случае, я узналмного о разработке схемы базы данных.Вот уроки, которые я выучил:

  • Не пытайтесь сложить все в одну и ту же таблицу: крайне важно правильно определить сущности, прежде чем определять, какие таблицы вам нужны.Я начал с двух таблиц, для видео и темы.Но оказывается, что подходящая схема БД для моей спецификации включает в себя таблицы для видео и ресурсов.
  • Не храните массивы в столбцах: используйте правильную стратегию для определения отношений между сущностями.Если у вас есть отношения «один к одному» или «один ко многим», используйте идентификаторы сущностей и внешние ключи.Если у вас есть отношения «многие ко многим», то правильный шаблон проектирования - это создание выделенной таблицы только для создания отношений между сущностями.Это позволит вам использовать предложения JOIN в ваших запросах для объединения всех данных.
  • Когда вы думаете о производительности, подумайте об INDEX: в зависимости от структуры таблицы, используя любой индексили составной индекс может улучшить производительность запросов.
  • Не пытайтесь получить все в одном большом запросе: вы определенно можете, но с отдельными запросами для частей данных, которые вам нужны (включеномой пример: один запрос для получения всех тем для курса, один для получения всех видео для курса, один для получения ресурсов для курса) окупается организацией кода и удобочитаемостью.

Я не знаю, правильно ли я со всем выше, но это то, что я узнал до сих пор. Надеюсь, это поможет кому-то еще.

Ответы [ 3 ]

1 голос
/ 23 марта 2019

В простейшей форме, при условии, что отношения между многими не много:

Course                Theme
--------              --------
CourseID <--+         ThemeId
Name        |         Name
            +------   CourseID
            |
            |      
            |         Video
            |         --------
            |         VideoID
            |         Name
            |         Length
            +------   CourseID
            |
            |
            |         Resource
            |         --------
            |         ResourceID
            |         Name
            +------   CourseID

В этой форме курс может иметь много тем, много видео и много ресурсов;но каждая тема, видео и ресурс могут иметь только один курс.

Однако я не думаю, что вы этого хотите.

Я бы больше склонялся к

                      Course             Theme
                      --------           --------
            +---->    CourseId    +--->  ThemeId
            |         Name        |      Name
            |         ThemeId ----+      
            |
            |      
            |         Video
            |         --------
            |         VideoID
            |         Name
            |         Length
            +------   CourseID
            |
            |
            |         Resource
            |         --------
            |         ResourceID
            |         Name
            +------   CourseID

Это позволяет курсу иметь только одну тему, но много видео и ресурсов.Это позволяет темам иметь более одного курса.

Но он все еще не вполне соответствует требованиям ...

Этот позволяет многим курсам использовать одну и ту же тему, а такжеиметь более одной темы:

                      Course         Course_Theme      Theme
                      --------       ------------      --------
            +---->    CourseId <----- CourseId   +-->  ThemeId
            |         Name            ThemeId ---+     Name
            |         ThemeId       
            |
            |      
            |         Video
            |         --------
            |         VideoID
            |         Name
            |         Length
            +------   CourseID
            |
            |
            |         Resource
            |         --------
            |         ResourceID
            |         Name
            +------   CourseID

В нынешнем виде у каждого курса может быть много тем, видео и ресурсов.Каждая тема может иметь много курсов.Каждое видео и ресурс относится к курсу (т. Е. Может иметь только один курс)

Если видео или ресурс могут содержать более одного курса, вам придется расширять его так же, как я делал с темами.


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

          Course         Course_Theme        Theme
          --------       ------------        --------
+---->    CourseId <---- CourseId                   
|         Name           ThemeId ----------> ThemeId
|                                            Name
|
|                        Course_Video        Video
|                        ------------        --------
+----------------------  CourseId                      
|                        VideoId ----------> VideoId
|                                            Name         
|                                            Length             
|                                                         
|                        Course_Resource     Resource
|                        ---------------     --------     
+----------------------- CourseId                        
                         ResourceId -------> ResourceId   
                                             Name         
                                             Url, etc.    

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

Themes per course
SELECT T.* 
FROM COURSE C
INNER JOIN COURSE_THEME CT ON CT.COURSEID=C.COURSEID
INNER JOIN THEME T ON CT.THEMEID=T.THEMEID 
WHERE {insert your search conditions on course}

or, if you know CourseId:

SELECT T.*
FROM THEME T
INNER JOIN COURSE_THEME CT ON T.THEMEID = CT.THEMEID
WHERE CT.COURSEID = ?


likewise,

Videos per course
SELECT V.*
FROM COURSE C
INNER JOIN COURSE_VIDEO CV ON CV.COURSEID=CV.COURSEID
INNER JOIN VIDEO ON CV.VIDEOID=V.VIDEOID
WHERE {insert your search conditions on course}

or, if you know the CourseId:

SELECT V.*
FROM VIDEO V
INNER JOIN COURSE_VIDEO CV ON CV.VIDEOID = V.VIDEOID
WHERE CV.COURSEID = ?

to select the sum of the video lengths per course,

SELECT SUM(LENGTH) AS TOTAL
FROM VIDEO
INNER JOIN COURSE_VIDEO CV ON CV.VIDEOID = V.VIDEOID
WHERE CV.COURSEID = ?
GROUP BY CV.COURSEID

Now, the tricky part is videos per theme.  I am making an assumption here:  the set of videos per theme is the same as the set of videos per course per theme.

The long way around:

SELECT V.*
FROM VIDEO V
INNER JOIN COURSE_VIDEO CV ON VIDEO.VIDEOID = CV.VIDEOID
INNER JOIN COURSE C ON COURSEID = CV.COURSEID
INNER JOIN COURSE_THEME CT ON C.COURSEID = CT.COURSEID
INNER JOIN THEME T ON CT.THEMEID = T.THEMEID
WHERE THEMEID = ?

Blech. You can cut out the middlemen:

SELECT V.*
FROM VIDEO V
INNER JOIN COURSE_VIDEO CV ON VIDEO.VIDEOID = CV.VIDEOID
INNER JOIN COURSE_THEME CT ON CV.COURSEID = CT.COURSEID
WHERE CT.THEMEID = ?

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


Обновление

Несмотря на то, что у меня были курсы в качестве корня, даже если темы являются корневыми,не сильно меняются:

          Theme          Course_Theme        Course
          --------       ------------        --------
+---->    ThemeId <----  ThemeId                   
|         Name           CourseId ---------> CourseId
|                                            Name
|
|                        Theme_Video         Video
|                        ------------        --------
+----------------------  ThemeId                      
|                        VideoId --------->  VideoId
|                                            Name         
|                                            Length             
|                                                         
|                        Theme_Resource      Resource
|                        --------------      --------     
+----------------------- ThemeId                        
                         ResourceId ------>  ResourceId   
                                             Name         
                                             Url, etc.    

В этой конфигурации у курсов есть видео и ресурсы через ThemeId, то есть:

SELECT V.*
FROM COURSE_THEME CT 
INNER JOIN VIDEO_THEME VT ON VT.THEMEID = CT.THEMEID
INNER JOIN VIDEO V ON V.VIDEOID = VT.VIDEOID
WHERE CT.THEMEID = ?
1 голос
/ 23 марта 2019

Создание схемы

Шаг 1: Определить сущности и их атрибуты

  • Курс (удостоверение личности, название, описание)
  • Тема (удостоверение личности, название, описание)
  • Видео (удостоверение личности, название, описание, продолжительность)
  • Ресурс (ID, заголовок, URL)

Шаг 2: Определить отношения

  • Тема => Курс
  • Видео => Тема
  • Ressource => Тема

Шаг 3. Создание таблиц

  • курсы
    • ID (PK)
    • название
    • описание
  • темы
    • ID (PK)
    • course_id (FK)
    • название
    • описание
  • видео
    • ID (PK)
    • theme_id (FK)
    • название
    • описание
    • duratation
  • Ressources
    • ID (PK)
    • theme_id (FK)
    • название
    • 1072 * URL *

Если тем могут обмениваться видео и ресурсами , то это будет отношение "многие ко многим" . В этом случае вам понадобятся отдельные таблицы для этих отношений. Удалите столбец theme_id из videos и ressources и добавьте следующие таблицы:

  • themes_videos
    • theme_id (PK) (FK)
    • video_id (PK) (FK)
  • themes_ressources
    • theme_id (PK) (FK)
    • ressource_id (PK) (FK)

Здесь вы должны определить составные первичные ключи для (theme_id, video_id) и (theme_id, ressource_id). Также создайте обратные индексы для (video_id, theme_id) и (ressource_id, theme_id).

Получение данных

Предполагая, что вы знаете идентификатор курса (который равен 123), затем вы можете получить связанные данные (из схемы многие-ко-многим ) со следующими запросами (которые вы выполняете один за другим):

select c.*
from courses c
where c.id = 123;

select t.*
from themes t
where t.course_id = 123;

select distinct v.*
from themes t
join themes_videos tv on tv.theme_id = t.id
join videos v on v.id = tv.video_id
where t.course_id = 123;

select distinct r.*
from themes t
join themes_ressources tr on tr.theme_id = t.id
join ressources r on r.id = tr.ressource_id
where t.course_id = 123;

Затем составьте ваш массив / объект из полученных данных в PHP.

Performance

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

0 голосов
/ 23 марта 2019

Структура таблицы

Создайте таблицы, подобные изображению, как показано, и используйте время кодирования / декодирования json ввода / вывода. В запросе вы можете иметь общее время из таблицы.

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