У меня есть 3 таблицы Mysql:
[block_value]
- id_block_value
- file_id
[метаданные]
- id_metadata
- имя_метаданных
[metadata_value]
- мета_ид
- стоимость
- blockvalue_id
В этих таблицах есть пары: metadata_name
= value
И список пар заключен в блоки (id_block_value
)
(A) Если мне нужна высота = 1080:
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "height" and value = "1080");
+---------+
| file_id |
+---------+
| 21 |
| 22 |
(...)
| 6962 |
(...)
| 8146 |
| 8147 |
+---------+
794 rows in set (0.06 sec)
(B) Если мне нужно расширение файла = mpeg:
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "file extension" and value = "mpeg");
+---------+
| file_id |
+---------+
| 6889 |
| 6898 |
| 6962 |
+---------+
3 rows in set (0.06 sec)
НО, если я хочу:
- А и Б
- A or B
- А а не Б
Тогда я не знаю, что лучше.
Для A or B
я попробовал A union B
, который, кажется, помогает.
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "height" and value = "1080")
UNION
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "file extension" and value = "mpeg");
+---------+
| file_id |
+---------+
| 21 |
| 22 |
| 34 |
(...)
| 6889 |
| 6898 |
+---------+
796 rows in set (0.13 sec)
Для A and B
, поскольку в Mysql нет intersect
, я попробовал A and file_id in(B)
, но посмотрите на производительность (> 4mn)...
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "height" and value = "1080")
and file_id in(
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "file extension" and value = "mpeg"));
+---------+
| file_id |
+---------+
| 6962 |
+---------+
1 row in set (4 min 36.22 sec)
Я тоже пробовал B and file_id in(A)
, он намного лучше, но я никогда не узнаю, какой из них поставить первым.
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "file extension" and value = "mpeg")
and file_id in(
SELECT DISTINCT file_id
FROM metadata_value MV
INNER JOIN metadata M ON MV.meta_id = M.id_metadata
INNER JOIN block_value BV ON MV.blockvalue_id = BV.id_block_value
WHERE (metadata_name = "height" and value = "1080"));
+---------+
| file_id |
+---------+
| 6962 |
+---------+
1 row in set (0.75 sec)
Итак... что мне теперь делать? Есть ли лучший способ для логических операций? Любой совет? Я что-то пропустил?
EDIT: как выглядят данные:
Эта база данных содержит строку в таблице FILE
для каждого вставленного аудио/видеофайла:
- 10, /путь/к/файлу.тс
- 11, /путь/к/file2.mpeg
Для каждой потенциальной информации есть строка в таблице METADATA
:
- 301, высота
- 302, расширение файла
Затем строка в таблице BLOCK
определяет контейнер:
- 101, Видео
- 102, Аудио
- 104, Генерал
Файл может иметь несколько блоков метаданных, таблица BLOCK_VALUE
содержит экземпляры БЛОКОВ:
- 402, 101, 10 // Видео 1
- 403, 101, 10 // Видео 2
- 404, 101, 10 // Видео 3
- 405, 102, 10 // Аудио
- 406, 104, 10 // Общие
В этом примере файл 10 имеет 5 блоков: 3 видео (101) + 1 аудио (102) + 1 общий (104)
Значения хранятся в METADATA_VALUE
- 302, 406, "ts" // расширение файла, общее
- 301, 402, "1080" // высота, Видео 1
- 301, 403, "720" // высота, Видео 2
- 301, 404, "352" // высота, Видео 3