Підзапит в умови ON для LEFT JOIN а MySQL

Я перекопав весь стековерфлів і втомив гугл, але я так і не зрозумів, чому MySQL запит (нижче) працює не правильно. Прошу простягнути руку допомоги або жбурнути в обличчя доку).Завдання: Потрібно отримати найсвіжішу дату з таблиці статистики для кожного користувача. ER-діаграма (спрощена):

mysql
SQL запит:

Проблема: Чому не працює LIMIT за умови WHERE у підзапиті? Можна отримати дату простим запитом, але мені потрібно отримати додаткові поля, які я не вказував у спрощеній схемі. І таких полів

5, тобто. буде 5 підзапитів. Що буде швидше не впевнений, але поки що схиляюся що LEFT JOIN буде швидше. Та й питання вже принципове — пів дня вбив.

Заздалегідь дякую за допомогу.

У результаті, я додав сурогатний PK, замість трьох складових полів. Якщо не зважати на денормалізацію БД, вважаю це оптимальним рішенням. Підсумковий запит:

Я отримую необхідні мені дані - всі поля останнього запису таблиці stats з будь-яким типом (можна вказати конкретний тип) для кожного користувача. При цьому сортування за ID буде швидше, ніж за датою. Запис для JOIN'а тепер однозначний, ситуація вибіркою кількох записів статси з однаковою датою вирішена. Залишилося прогнати на більш-менш реальному наборі даних та оцінити продуктивність. Всім дякую за допомогу.

Розумію, що ця не та відповідь, якої ви чекаєте, але якщо не помиляюся, ось такий запит працюватиме правильно:

WHERE U.id =1 - за бажанням :)

Вибачте, може, я не дуже зрозумів. Але, на мою думку, можна якось простіше:

не перевіряв, чесно говорю.

Не працює ваш запит тому, що ви з підзапиту назад вибираєте той самий user_id, який «подали всередину». Іншимисловами, ваш запит ідентичний наступному:

Як правильно зробити, вже написали вище. ІМХО, варіант із угрупованням буде найкраще, і читабельніше теж. Хоча краще порівняйте продуктивність реальних даних. Про всяк випадок, тримайте сам запит:

Читаю: Не працює ваш запит тому, що ви з підзапиту назад вибираєте той же user_id, який «подали всередину» ОК, я передаю за умови склеювання просто число = ID користувача:

Чому ж я очікую, що використовуючи умову LIMIT 1 у підзапиті — має бути «склеєний» лише один запис із таблиці stats? А з таким запитом до кожного користувача джойняться всі записи з stats.

Загалом я тут подумав, правильний шлях це дороблений варіант shedal:

За ідеєю при такому запиті буде лише три вибірки. Ну і, природно, зв'язка user_id + date має бути унікальною, інакше записи задвояться, але це можна вирішити за допомогою DISTINCT або того ж GROUP BY.

Виходячи з первісного завдання, я не зовсім розумію призначення другого джойна LEFT JOIN stats AS s. У лабораторному прикладі user_id + date нічого не винні бути унікальними, оскільки PK складається з user_id + date + type . Але це начебто як суті завдання не змінює — потрібно отримати один останній запис статистики.

1. Наприклад потрібно отримати останню статсу за будь-яким типом (type):

…отримали. На тестових даних все сходиться. Другий джойн не потрібен.

2. Потрібно отримати останню статистику з урахуванням типу:

Я поки що не бачу потреби у додатковому джойні. Може, у нас не сходяться уявлення про умови завдання? Або в моєму запиті (без того джойна) ми будемо отримувати додаткові поля таблиці stats у випадковому порядку через угруповання?

А якщо LIMIT вбрати, він з усіма записами з'єднає? У SQLite,наприклад, можна використовувати внутрішній ідентифікатор ряду без ліміту, тобто це було б:

але там явно обговорюється, що (SELECT y .) у виразі повертає перший збіг запис, а не всі; не знаю, як з цим у MySQL.

10 000, по кожному користувачеві щодня додається до 2-3 тисяч записів статистики. Тут питання в тому, що є тип запису в таблиці статистики. І тримати останню дату доведеться за кожним типом. Типи додаються при необхідності, передбачається 10-20 типів у результаті. Виходить, у статистиці є припустимо, 3 поля з даними користувача + дата + тип. Якщо зберігати останні дані історії (статистики) у самій таблиці user: 1. При необхідності потрібно буде додавати нові поля, коли з'являється новий тип статистичних даних; 2. У результаті полів буде 3 * N типів, це ще плюс 30-60 полів до основних даних користувача. Якось теж не гуд. Може у Вас є якісь думки з цього приводу? Дякую.

Якщо не подобається патерн зі створенням атрибутів статистики по суті клієнта, спробуйте тоді, у найпростішому випадку, тримати одну таблицю для актуальних значень статистики з PK [user_id, stat_type] + таблицю з історичними значеннями (аудит таблицю), яку супроводжуватимете на тригерах, у разі зміни першої.

У ще більш хитрому випадку ці таблиці можна і об'єднати (як у вас зараз — спочатку), але для прискорення запитів додати прапор current, який буде або 1 або NULL + складовий індекс [current, user_id]. Геммор тригерів із попереднього варіанту піде, замінить його геммор супроводу прапора current. Усілякі варіанти організації подібних історичних довідників з "+" та "-" описані у вікіпедійній статті на тему «slowly changing dimensions».

Поставте собі питання, крім багтрейсів та рідкісноїаналітики, Вам дійсно важливо ганяти запити на отримання та історичних та актуальних даних по одній таблиці? Якщо ні - перший варіант саме те + партикування та видалення найстаріших партицій на шедулері (за смаком).

раз в півроку). А тут динаміка типів статистики досить динамічна. І мене бентежить підсумковий набір + ". 30-60 полів до основних даних користувача." При цьому дані статистики оновлюються за кожним записом

раз на хвилину. Вам дійсно важливо ганяти запити на отримання та історичних та актуальних даних по одній таблиці? Ні, але денормалізацію зазвичай проводжу після проектування повної структури БД. Я просто прикидаю що кількість запитів на вибірку = запитів на вставку, ну може SELECT'ів буде на 20% більше. У оригіналі це користувачі, а проксі сервера і після запиту і відпрацювання проксі — логуємо результат. Користувачами, мабуть, не варто було називати лабораторну сутність, надто спростив. Виходить для однієї таблиці статистики - ми вставили новий лог і забули. А у разі додаткової таблиці з актуальними даними, потрібно щоразу перевіряти існування запису і або вставляти нову, або оновлювати існуючу. Ось цей момент мене і бентежить. Я з ходу не можу сказати, що буде швидше. І як краще розподілити навантаження – на вибірку чи вставку. Схоже, потрібно перевіряти на середніх обсягах даних. Дякую за підказку та за статтю, не читав.