Я пытаюсь оптимизировать SQL-запросы в Akonadi и столкнулся со следующей проблемой, которую, по-видимому, нелегко решить с помощью SQL, по крайней мере для меня:
Предположим, что следующая структура таблицы (должна работать в SQLite, PostgreSQL, MySQL):
CREATE TABLE a (
a_id INT PRIMARY KEY
);
INSERT INTO a (a_id) VALUES (1), (2), (3), (4);
CREATE TABLE b (
b_id INT PRIMARY KEY,
a_id INT,
name VARCHAR(255) NOT NULL
);
INSERT INTO b (b_id, a_id, name)
VALUES (1, 1, 'foo'), (2, 1, 'bar'), (3, 1, 'asdf'),
(4, 2, 'foo'), (5, 2, 'bar'), (6, 3, 'foo');
Теперь моя проблема - найти записи в a
, в которых отсутствуют name
записи в таблице b
. Например. Мне нужно убедиться, что каждая запись в a
содержит как минимум name
записей "foo"
и "bar"
в таблице b
. Следовательно, запрос должен возвращать что-то похожее на:
a_id = 3 is missing name "bar"
a_id = 4 is missing name "foo" and "bar"
Поскольку обе таблицы в Akonadi потенциально огромны, производительность крайне важна.
Одним из решений в MySQL будет:
SELECT a.a_id,
CONCAT('|', GROUP_CONCAT(name ORDER BY NAME ASC SEPARATOR '|'), '|') as names
FROM a
LEFT JOIN b USING( a_id )
GROUP BY a.a_id
HAVING names IS NULL OR names NOT LIKE '%|bar|foo|%';
Мне еще предстоит измерить производительность завтра, но я сильно сомневаюсь, что это будет быстрым для десятков тысяч записей в a
и в три раза больше для b
. Кроме того, мы хотим поддерживать SQLite и PostgreSQL, где, насколько мне известно, функция GROUP_CONCAT
недоступна.
Спасибо, спокойной ночи.