логин: 
Другие записи за это число:
2011/03/11 - Редактор файлов
<< предыдущая заметкаследующая заметка >>
11 марта 2011
Вопрос по MySQL

ВНИМАНИЕ!
НЕ ОБНОВЛЯЙТЕ ПОКА ДВИЖОК!

В нем происходят изменения, но пока не все готово! Например, сейчас выдается ошибка на страницах комментариев, не работает создание новой заметки, не работает автообновление страницы при записи отредактированной заметки (надо перегрузить) и еще куча мелочей.

Вообще с моей стороны это вообще когда-то было очень непродуманным шагом, совмещать в одном лице экспериментальную бету и сервер-матку. Когда я закончу новую версию админки (уже скоро), там по умолчанию сервер обновления будет Stable — lleo.aha.ru/dnevnik/ или даже SuperStable lleo.aha.ru/, но никак не бета lleo.aha.ru/blog/

Тем, кто успел обновиться, советую зайти в /install.php и нажать кнопку «back»


UPD: Всем спасибо за советы! Правильный ответ (от illand с небольшими уточнениями по справочнику) такой:

SELECT t.*,GROUP_CONCAT(CONCAT_WS('=',o.name,o.value) SEPARATOR ';') as opt
FROM `ZAPISI` as z LEFT JOIN `OPT` as o USING (`num`)
WHERE `num`='123'

в выдаче добавляется:

opt: comments=on;comments_mode=tree;comments_screen=off;preformat=0

Однако больше всего мне пришелся по душе совет хранить опции в поле text как serialize(). Пожалуй, это самое умное, что можно придумать для такой задачи, когда опции хрен знает какие, но никогда никакого поиска по ним не потребуется — это опции отображения заметки и ее комментариев.

Было:

Сейчас существует таблица заметок, пример записи в таблице ZAPISI:

numtextcommentscomments_modecomments_screenpreformat...
123Сегодня ночью мне снился сон, будто бы я...ontreeoff0...
124...

Поле 'text' может и занимать мегабайт (текст романа), а вот опции — мелкие, чаще всего enum. Проблемы две: обычно пользователь не меняет их, в большинстве заметок они одинаковы. Проблема вторая серьезнее: я не знаю, какие опции понадобятся в будущем. Запрет на комментарии со ссылками? Текст для подписывания тех фотографий, которые посетители загрузят в комментарий именно к этой заметке («конкурс Сиськи Года в блоге Васи»)? Количество допустимых комментариев от каждого пользователя в этой заметки? Неизвестно.

Поэтому здравой мыслью было бы завести таблицу OPT, и там хранить опции:

таблица ZAPISI:

numtext
123Сегодня ночью мне снился сон, будто бы я...

таблица OPT:

idnumnamevalue
1123commentson
2123comments_modetree
3123comments_screenoff
4123preformat0

Вроде бы все хорошо, но проблема оказалась в том, что MySQL не умеет делать на этот счет один корректный запрос вида:

SELECT * FROM `ZAPISI` as z LEFT JOIN `OPT` as o ON z.num=o.num WHERE z.num='123'

То есть, MySQL конечно запрос выполняет, но выдает не запись 123, а 4 записи по числу найденных в OPT, в каждой пристыковывая text из ZAPISI (а это, напоминаю, роман на 1мб).

Нужен совет. Вариант, что все-таки существует в MySQL пример записи для подобного случая, просто я не знаю, пока отметается — вроде я поизучал вопрос. Поэтому вариантов вижу два:

1. Надо делать два запроса к MySQL:
SELECT * FROM `ZAPISI` WHERE num='123'
SELECT name,value FROM `OPT` WHERE num='123'

2. Не надо разбивать таблицу на две. Поскольку обычно опции короткие типа enum(0,1,'yes','off'), надо просто дописывать в таблицу `ZAPISI` новые имена переменных по мере необходимости.

Вопрос в том, что окажется ДЕШЕВЛЕ в плане ресурсов. Потому что хрен его знает, насколько крупным окажется в итоге движок и его пользователи, и лучше такие вещи продумать заранее. То есть, вариант 1 или 2 — не похуй, нужно выбрать тот, который экономнее в плане ресурсов.

<< предыдущая заметка следующая заметка >>
пожаловаться на эту публикацию администрации портала
архив понравившихся мне ссылок
Оставить комментарий
Windows Safari Chrome
 Австралия
0
0
Hello,
Will example from Oracle's sql syntax help? (It should be reasonably similar in its standard bits I imagine, but I have no access to MySql to verify their syntax..)
Cheers, -Olga..

select 0 as id, z.num as num, 'text' as name, z.text as value
from zapisi z
where num = 123
union all
select o.id, o.num, o.name, o.value
from opt o
where num = 123;

ID NUM NAME VALUE
------- ---------- -------------------- ----------------
0 123 text I had a dream...
1 123 comments on
2 123 comments_mode tree
3 123 comments_screen off
4 123 preformat 0
Nokia-E90 Safari
 Москва
0
0
Leonid Kaganov
Спасибо, но система рассчитана на MySQL.
Mac Firefox
1
0
На самом деле, тот пример будет работать и на MySQL.
Linux Opera
0
1
lleo.me/[email protected]Алексей
Учимся добавлять столбцы.

ALTER TABLE tbl ADD field type AFTER fld;
где:
tbl = "Название таблицы в которую добавляем"
field = "Поле которое добавляем"
type = "Тип данных для нового поля"
fld = "После какого поля"

Но MySQL не нужен. И в SQlite оно имеется без излишеств.

А вообще все ценное и/или большое надо хранить в файлах!
Так если же иначе то создать еще одну таблицу может быть не лишним (быдлокодом не будет точно), но такого же вида т.е.:

num | comments | comments_mode | comments_screen | preformat
123 | on | tree | off | 0


Ведь добавлять столбцы мы умеем.

Ессессно, первая тогда: num | text

Но лучше бы это были файлы:
include "messags/".$num.".html";
Mac Safari Chrome
0
0
lleo.me/[email protected]_rr
Заметки — не настолько большие, чтобы была необходимость хранить их в файлах. И обращение к файловой системе намного дороже, чем запрос к базе.
Nokia-E90 Safari
 Москва
0
0
Leonid Kaganov
Столбцы добавлять и дурак может. Вопрос был другой.
Linux Opera
0
0
lleo.me/[email protected]Алексей
Я написал, что разделить точно не помешает, при том, что новая будет фактически куском старой. А выносить в такой вид, как предложили вы не вижу смысла.

Кстати, у вас правда есть такие значения как off/on? (true/false не осилили?)
Windows Opera
 Санкт-Петербург
0
1
[email protected] (217888993625)
Интуитивно кажется, что лучше два запроса.
Если попытаться обосновать, то мысль такая: это многопользовательская система, запросов и так много будет, от того, что их станет чуть больше - ни жарко ни холодно.
Windows Safari Chrome
0
0
Sling (#824708)
Если есть подозрения что база будет сильно нагружена в будущем (именно если рассчёт на то что будет работать на пределе возможностей железа на котором стоит), лучше оставить структуру как есть. То что таблица "широкая", никак на производительность не повлияет. Индексы строятся по адресам записей или страниц (не знаю как именно в MySQL), и количество колонок работу не замедлит.

Если же эстетические предпочтения и "правильный" подход (в конце концов, производительность не так уж и упадёт по идее) имеют более высокий приоритет, то разносить нужно. Так движок просто понятнее станет, в конце концов, что тоже немаловажно. И в таком случае эту таблицу с опциями советую делать универсальной. Тоесть добавить ещё что-то вроде колонки SettingType, который может принимать значения User, Post, Engeene. И хранить там все опции. Для юзера Num тогда будет номером юзера, для - заметки он становится уже номером заметки. Для движка может быть 0 или NULL например. Будет удобно работать с опциями всего через один механизм, принимающий имя опции, тип объекта и номер объекта.
Я именно с таким подходом хранения сеттингов на текущем проекте столкнулся.
Windows Opera
0
0
Wot (#458830)
первое и самое важное - дешевле вообще не бывает. Бывает меньше CPU или меньше памяти, причем последнее делиться на лучше кэшируемое и меньше размером. И зачастую нельзя совместить все это вместе.

второе - развернуть таблицу можно через union, но надо знать конкретные значения ключей. Но это "через жопу" однозначно.

Если надо все опции сразу - значить они должны быть в одной строке ZAPISI, если опции опциональны - то надо делать запросы с указанием ключа
SELECT o.value FROM `ZAPISI` as z LEFT JOIN `OPT` as o ON z.num=o.num WHERE z.num='123' and o.name='comments'

Если посмотреть уже существующие реализации, то там смешанный подход - часть опций в виде столбцов и жестко привязана к тексту записей, часть - в отдельной таблице.
Windows Firefox
0
0
Дополнительный запрос на общем фоне не сильно прибавит нагрузки. При этом если задать значения по умолчанию, то во второй таблице можно хранить значения только отличающиеся от значений по умолчанию - > экономия места.

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

ПО пагинации комментариев - мне кажется ответы на комментарий должны находиться на той же странице, что и первый комментарий. Сейчас это не так.
Windows Safari Chrome
0
0
В текстовом поле опции хранить можно, если поиск по опциям не нужен. А то выбор всех заметок с опцией "опубликован = on" превратится в половое извращение.
Windows Firefox
0
0
STFG: mysql pivot
Windows Safari Chrome
0
0
Если все-таки не отметать вариант одного запроса, то можно добыть все за один раз так:
SELECT
num, text,
(SELECT GROUP_CONCAT(name ORDER BY name) FROM OPT WHERE num = Z.num) AS names
(SELECT GROUP_CONCAT(value ORDER BY name) FROM OPT WHERE num = Z.num) AS values
FROM
ZAPISI Z

массив опций после этого формируем на PHP:
$opts = array_combine($names,$values);

теперь, например, $opts['comments'] == 'on'
Windows Safari Chrome
0
0
в смысле
$opts = array_combine(split(',',$names),split(',',$values));
Windows Safari Chrome
0
0
Ну а из предложеных двух вариантов - конечно второй! Таблицы надо обязательно разбивать! Два запроса не сильно утяжелят механизм (я бы сказал, что может даже меньше, чем предложенный мной вариант с GROUP_CONCAT).
Только не совсем понятно, зачем id в таблице опций? Должно быть PRIMARY KEY (num, name)
Windows Firefox
1
0
lleo.me/[email protected]Артем Павлов
Оффтоп

Мне кажется, каменты из одного треда должны быть на одной странице...
Linux Firefox
 Москва
0
0
Ты прав. Но позже.
Linux Firefox
 Москва
0
0
Сделал деление страниц только по комментариям первого уровня. Но вот счетчики страниц слетели - откуда им знать-то про уровни.
Linux Firefox
 Москва
0
0
Предлагаю число страниц и число комментариев записывать в опции заметки - всякий раз при добавлении комментария.
Linux Firefox
 Москва
0
0
3
Windows Safari Chrome
 Санкт-Петербург
0
0
[email protected] (217888993625)
Ещё вариант: все эти мелкие переменные хранить в одном поле в виде текстовой строки. Обрабатывать программно, без эскуэля.
Windows Safari Chrome
0
0
mysql_query("SELECT `opt`,`num` FROM `dnevnik_zapisi` WHERE `num`='259' AND `Comment_view`!='off' AND `Access` IN ('all','podzamok')")
Unknown column 'Comment_view' in 'where clause'
Linux Firefox
 Москва
0
0
Если это в вашем движке такое - будем думать.
Если в моем - не обращайте внимание, идет отладка.
Linux Opera
0
0
Предварительная оптимизация -- зло.

всего комментариев: 25

<< предыдущая заметка следующая заметка >>