LINUX.ORG.RU

Его крокейшество о вредности СУБД, если архитектурно она для программ, а не живого человека

 ,


0

6

Давно уже что-то про Столярова Croco ничего не было =) А тут он повод недавно дал, расписав почему считает недопустимым использовать СУБД в архитектуре при проектировании софта. То есть, если для каких-то программ нужно хранение данных, его надо индивидуально под программу делать, а не подключать базы данных.

Можно обсудить. В принципе я сам не люблю для локальных данных применять базы данных, часто достаточно просто текстовых файлов и это даже надежно и быстро. Но в целом каким-то луддизмом отдает. Его сообщение ниже:

http://www.stolyarov.info/guestbook#cmt97

==============

Я придерживаюсь принципа несколько более узкого: недопустимо создание, распространение и использовние программ, для работы которых требуется СУБД.

Причины можно назвать, например, такие:

  1. СУБД — это лишняя внешняя зависимость, при том что вообще любые внешние зависимости суть хамство в отношении пользователей и мейнтейнеров;
  2. СУБД требует трудозатрат на установку, настройку и дальнейшее администрирование;
  3. СУБД способна упасть (и да, падает намного чаще, чем, скажем, тот же апач — вообще пока мои сайты жили на «традиционной» CMSке, именно СУБД была причиной всех случаев downtime моих сайтов, за исключением одного, когда на сервере физически осыпался жёсткий диск);
  4. СУБД требует от пользователя постоянно обновлять навыки, которые, возможно, больше ни для чего не нужны;
  5. СУБД хранит информацию пользователя в неочевидном для него виде; этим грешат не только СУБД, конечно, но СУБД мало того что хранят всё в бинарных файлах, которые без самой СУБД даже думать нечего разобрать, они ещё и вводят дополнительный слой хаотизации в виде схемы БД, провоцируя разработчиков софта на внедрение «решений», единственное «описание» которых остаётся в голове у автора;
  6. СУБД требует изрядных вычислительных мощностей и крадёт (а вовсе не повышает, как почему-то многие уверены) производительность.

Я, заметим, не рискну утверждать, что СУБД как сущность вообще никогда не может ни для чего применяться. Тут вопрос в том, кто на ком стоял: если главной целью является база данных как таковая, то есть вот имеется какой-то значительный объём разнородной, но при этом взаимосвязанной информации и стоит задача обеспечить его хранение и в нём поиск, причём никто заранее не знает, какие именно задачи будут решаться на этом массиве информации, какие именно поисковые запросы будут делаться и вот это вот всё, то да, СУБД вполне может оказаться адекватным решением, и даже для работы с ней могут создаваться вспомогательные программки. Это, конечно, не оправдывает существования языка SQL, который в любых его проявлениях представляет собой надругательство над здравым смыслом, но в целом СУБД как вид софта существовать, наверное, всё-таки может — но лишь в случаях, когда либо вообще нет никаких программ кроме неё самой, либо программы делаются для неё, а не она сама поддерживается для работы какой-то программы.

Всё это можно выразить и короче: СУБД, по-видимому, вполне имеет право на существование в ситуации, когда основным способом работы с ней будет непосредственное вбивание запросов на её языке запросов живым человеком. То есть когда именно вот это — основное, а всё остальное вспомогательное. В подавляющем большинстве случаев мы видим прямо противоположное: с СУБД как-то там общается некая программа (намного реже — больше одной программы, и это уже пограничный случай), а живой человек делает запросы либо только в рамках обслуживания всей системы, либо вообще никогда.

Когда же пишется некая программа, предполагающая применение для конкретных задач (а программы иначе, собственно, и не пишутся), и данные возникают исходя из этих задач, а не наоборот, то за саму идею задействования внешней СУБД нужно убивать на месте. Сугубо из санитарных соображений.

★★★★★
Ответ на: комментарий от PolarFox

в базах всё имеет объяснение. «вдруг» только вороны летают. поэтому иногда надо потратить время и разобраться, почему это произошло. а не просто в панике бежать куда-то на другой софт, который ещё не факт, что окажется менее глючным. да, любая база требует настройки. без этого никак.

у меня в постгресе ничего «вдруг» пока что не происходило. хотя я его тестировала специально на больших нагрузках и с кэшем, так как планировала довольно интенсивное применение.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от kaldeon

Однозначно, на любом ЯП. Как и многое другое: что-то выносим в асинхронщину, что-то в кэши, что-то на клиент, что-то в протокол — и в итоге от ЯП остаётся след в пол-копейки.

Вот это единственный случай, когда нужна зависимость от СУБД. А если, наоборот, СУБД используется только как хранилище объектов ЯП, то лучше использовать более адекватное решение.

monk ★★★★★
()
Ответ на: комментарий от monk

вывести последние N непустых дней из журнала записей

Select * from tbl_log where record !='' order by date desc limit 7?

Ну или is not null, если у тебя колонка record nullable.

leave ★★★★★
()
Ответ на: комментарий от leave

Не 7 записей, а 7 дней.

У тебя записи 2025-09-29 13:05:30, 2025-09-29 12:51:00, 2025-09-26 13:22:45, …

Надо вывести все за 2025-09-29, 2025-09-26, … (и ещё 5 дней).

monk ★★★★★
()
Ответ на: комментарий от kaldeon

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

это ещё не считая затрат на железо. говнокод, как правило, ещё и очень жруч до ресурсов.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

Я не против кеширования до тех пор пока оно может оставаться невидимой нам деталью реализации подсистемы и не «протекать» наружу. Кеширование в БД — это хорошо, но они приложили много усилий чтобы не нарушить ACID и прочие гарантии, которые БД обещает.

Возможно более знакомый местным пример. Кеширование операций с ФС — замечательная штука, но ровно до тех пор пока нам гном не отрапортовал что файл на флешки был записан за 8 секунд, а нам ещё 6 минут sync’а ждать.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

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

про флэш: ты же понимаешь, как устроен флэш и почему он кэшируется и нужен sync? (глядя с видом из известного мема) понимаешь, да?

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

Ну… статистика по табличке перевалила за threshold когда надо предпочитать такие-то виды индексов другим видам индексов. Но планировщик неправильно перевёл свои попугаи в секунды, и стал использовать весьма неудачный для данной операции индекс, который вообще задумывался для совсем другой задачи. А неудачный индекс был добавлен чуть ли не за месяц до этого, поэтому в чём дело поняли не сразу, а только минут через полчаса.

Можно до посинения тюнить коэффициенты попугаев планировщика, но всё равно в предварительной оценке плана окажутся неточности, которые иногда могут вот так взрывоопасно усилиться, особенно если кусок плана оказался где-то в иннер-лупе.

PolarFox ★★★★★
()
Ответ на: комментарий от Iron_Bug

так тормоза в отдельных запросах ACID и не нарушают

Я про то, что авторы кеша в базах шишки уже набили, и детских багов как от самопального кеша от них не ждёшь.

про флэш: ты же понимаешь, как устроен флэш и почему он кэшируется и нужен sync? (глядя с видом из известного мема) понимаешь, да?

Я, как пользователь, хочу чтобы когда окошко копирования файлов пропало, я мог безо всякого «безопасного извлечения» отцепить флешку, и чтобы на ней были эти файлы. Если это не так, то интерфейс меня обманул. А если «безопасное извлечение» занимает не полсекунды, а 10 минут, то интерфейс меня очень обидным образом обманул.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

Но планировщик неправильно перевёл свои попугаи в секунды, и стал использовать весьма неудачный для данной операции индекс

если вы дошли до этой детали, вы написали разработчикам о баге? или вы не уверены, что дело было именно так.

база пытается выполнять запросы быстрее. что-то получается, что-то нет. это физический мир, его нельзя сделать идеальным. можно только пытаться что-то оптимизировать, смотреть на результаты и повторять эксперименты.

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

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 2)
Ответ на: комментарий от Iron_Bug

Это же не баг, это вполне себе разумное в 97% случаев поведение системы. Не повезло нарваться, когда при тех же вводных оказался в 3%. Можно, конечно, попросить авторов СУБД, за которую мы не платим, поколдовать над edge-case’ом, но в нашем случае оказалось проще создать более хитрый индекс вместо неудачного, который уже не подхватывался планировщиком в случае «основного» запроса. Быстрее, чем искать где у постгреса багзилла, и как в неё писать.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

ну, то есть:

1) проблема решилась, хотя и через костыль

2) вы поленились найти багзиллу (ужасная по сложности задача), чтобы написать об этом странном поведении. хотя, возможно, вам бы подсказали правильное решение или улучшили код, чтобы впредь таких проблем не было.

и кто виноват, что разработчики об этом не знают?

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 1)
Ответ на: комментарий от Iron_Bug

проблема решилась, хотя и через костыль

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

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

Ну сайт в любом случае надо было чинить своими силами, нам даже полчаса простоя весьма неприятно. А потом сделали для себя выводы, и «нишевые» индексы добавляем только с хитрыми предикатами, чтобы они случайно не вылезли где не надо. И возможно всё таки поставим «замораживатель» планов.

А общаться с чужим проектом на тему очень нишевой проблемы, которую ещё наверняка трудно повторить, нам действительно лень, свою работу бы сделать.

и кто виноват, что разработчики об этом не знают?

Я и не виню постгрес или его разработчиков. Просто раз уж мы добавили постгрес в систему, то теперь приходится быть ещё и специалистом по постгресу.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

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

Вот это, кстати, основная проблема с ОРМами. Если при прямом доступе к СУБД хоть как-то можно вручную заточить запрос и индексы, то когда ОРМ сам формирует индексы и запросы, отладка производительности начинает напоминать чёрную магию. Например, производительность может резко поменяться от перемены порядка полей в запросе или порядка условий.

monk ★★★★★
()
Ответ на: комментарий от PolarFox

общаемся с удалённой системой к которой пинг 50мсек, и что нам лишняя 1мсек от питона.

urls = []
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0040.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0050.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0060.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0070.shtml")

Это общие рассуждения. Вот конкретная задача скачать «Войну и Мир» Толстого и перевести ее в текстовый формат с длинной строки в 70 символов. Сделать однопоточно на Ruby.

Команда запускается так ./upload_and_stdout.rb > all.txt

Что имеем по скорости?

Ruby:
# Download 2121.023 ms
# Convert to UTF-8 103.808 ms
# Remove \r 60.152 ms
# Strip HTML 331.474 ms
# Remove `-` 102.34 ms
# Make 70 symbols 920.447 ms
# To STDOUT 6.182 ms

Переведенный LLM код на Go:
Download 1222.453 ms
Convert to UTF-8 0.000 ms
Remove \r 4.915 ms
Strip HTML 195.624 ms
Remove `-` 588.275 ms
Make 70 symbols 532.536 ms
To STDOUT 32.242 ms

Длинней STDOUT потому что LLM версия не правильно режет строки.
Строки короче в 2 раза. Но суть та-же.

На обработку 90k строк общим весом 6Mb. При этом я «не в чем себе не отказывал», и склеивал колол строки так:

def line_to_70(line)
  l = line.split(" ")
  arr = []
  max = 70
  i = 0
  while i < l.size 
    if arr.empty?
      arr.push ""
    end
    if (arr[-1].size + l[i].size) < max
      arr[-1] += l[i] + " "
    else
      arr.push ""
      arr[-1] += l[i] + " "
    end
    i += 1
  end
  arr.reject{|x| x.empty?}
end
run
texts.map!{|text| 
  text
    .split("\n")
    .map{|l| l.empty? ? "" : line_to_70(l).join("\n")}
    .join("\n\n").gsub(/\n{4,}/,"\n\n") 
}
stop("Make 70 symbols")

И на это у меня ушла 1 секунда. Т.е. по это еще «терпимо» по классификации оценки работы. А все остальные операции уходят в «вполне себе хорошо». Код на Go только в 2 раза быстрей.

Есть таблица от Jakob Nielsen, где наглядно показывается как пользователь реагирует на задержки.

Время задержкиВосприятие пользователемРеакция/ощущение
0–100 мс⚡ Мгновенно (blazingly fast)Чувствуется как локальная реакция
100–300 мс🤔 Машина «думает» (machine thinking)Замечается микрозадержка
300–1000 мс (1 сек)⏱ Заметная паузаТерпимо, но внимание сбивается
1–3 сек💤 Медленно (slow)Пользователь отвлекается
3–10 сек😡 Очень медленно (very slow)Раздражение, риск закрыть сайт
>10 сек🚪 Уход (abandon)Пользователь уходит, если нет прогресса
lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 3)
Ответ на: комментарий от PolarFox

Я на питоне лет 10-15 пишу и хорошо знаком с его производительностью.

Про Python я рассказывать не буду, но вот у Ruby с Go в однопотоке на практических задачах может быть вполне сопоставимая скорость. Тут обработка строк при помощи Regex.

  • Sprip HTML: 331.474 ms Ruby 195.624 ms Go
  • Remove -: 102.34 ms Ruby 588.275 ms Go
# Ruby
# Strip HTML 331.474 ms
# Remove `-` 102.34 ms 
run 
texts = contents.map{|html| 
  html
    .gsub(/<!--.*?-->/m, '')
    .gsub(/ /, ' ')
    .gsub(/<\/?[^>]+>/, '') 
}
stop("Strip HTML")

run
texts.map!{|v| v.gsub(/(\s)-{2}(\s)/, '\1-\2')}
stop("Remove `-`")

// Golang (LLM translation from the Ruby source)
// Strip HTML 195.624 ms
// Remove `-` 588.275 ms
	run()
	commentRe := regexp.MustCompile(`(?s)<!--.*?-->`)
	tagRe := regexp.MustCompile(`</?[^>]+>`)
	for i, html := range contents {
		t := commentRe.ReplaceAllString(html, "")
		t = strings.ReplaceAll(t, " ", " ")
		t = tagRe.ReplaceAllString(t, "")
		contents[i] = t
	}
	stop("Strip HTML")

	run()
	dashRe := regexp.MustCompile(`(\s)-{2}(\s)`)
	for i, v := range contents {
		contents[i] = dashRe.ReplaceAllString(v, "$1-$2")
	}
	stop("Remove `-`")

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от lbvf50txt

Но ведь тут… всего 4 мб данных. Это ни о чём, я тоже питон возьму, ибо удобно и привык. Особенно если это одноразовые 4мб, а не часть какого-то постоянно запущенного конвейера, где разница в 2 раза это не секунды, а гораздо более осязаемые величины, вроде лишней серверной стойки.

PolarFox ★★★★★
()
Ответ на: комментарий от lbvf50txt

Ну и тут мы по сути сравниваем не скорость рантаймов этих языков, а скорость библиотечных функций по работе со строками. Которые, я не сомневаюсь, и в рубях, и в питоне, и в го весьма качественные. Думаю если переписать без итерации по строкам (мап строку по ньюлайнам же бьёт?), то скорость вообще сравняется.

Как только мы проводим в рантайме динамического языка какое-то нетривиальное количество времени, пользуемся бигинтами для всей арифметики (что происходит в питоне), пользуемся хешмапами из пяти элементов в качестве «объектов», то начинается сильная боль.

И у многих даже нет «ощущения» того, как быстро могут работать компьютеры. Они не знают когда их программа на питоне всего в полтора раза медленнее, чем могла бы быть на условном си, а когда раз в 50.

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

Но ведь тут… всего 4 мб данных

Вот именно, что тут целых несколько мегабайт строковых данных, пол миллиона слов над которыми проводится тестирование Regex. И не на синтетических данных, а парсится известный сайт до более менее удобочитаемого состояния текста.

# Input HTML:
$ wc full.html
  24898  589762 6971902 full.html
# After Ruby parsing:
$ wc all.txt
  86672  583196 6405282 all.txt
# After Golang (LLM translation) parsing:
$ wc allGo.txt
 121844  583196 6338347 allGo.txt
lbvf50txt
()
Ответ на: комментарий от PolarFox

Думаю если переписать без итерации по строкам (мап строку по ньюлайнам же бьёт?), то скорость вообще сравняется.

И у многих даже нет «ощущения» того, как быстро могут работать компьютеры. Они не знают когда их программа на питоне всего в полтора раза медленнее, чем могла бы быть на условном си, а когда раз в 50.

Дак перепишите. Возьмите мной представленную задачу и напишите на алгоритмически чистом Си с правильными подходами, с оценкой алгоритма, еще сделайте inplace, чтоб лишняя память не расходовалась. Опубликуйте код.

Сколько у вас времени уйдет? То-то и оно. Все эти разговоры о медленном Python и быстром С это больше форумнуе творчество «когда не горит».

Вот вам код на Ruby, если задумаете переписывать:

#!/usr/bin/env ruby

urls = []
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0040.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0050.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0060.shtml")
urls.push("http://az.lib.ru/t/tolstoj_lew_nikolaewich/text_0070.shtml")

def run
 $start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
end

def stop(name)
  finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  elapsed_ms = ((finish - $start) * 1000).round(3)
  STDERR.puts "#{name} #{elapsed_ms} ms"
end

def line_to_70(line)
  l = line.split(" ")
  arr = []
  max = 70
  i = 0
  while i < l.size 
    if arr.empty?
      arr.push ""
    end
    if (arr[-1].size + l[i].size) < max
      arr[-1] += l[i] + " "
    else
      arr.push ""
      arr[-1] += l[i] + " "
    end
    i += 1
  end
  arr.reject{|x| x.empty?}
end

require 'open-uri'
run
contents = urls.map{|url| URI.open(url, &:read)}
stop("Download")

run
contents.map!{|v| v.encode("UTF-8")}
stop("Convert to UTF-8")

run
contents.map!{|v| v.gsub("\r", "")}
stop("Remove \\r")

run 
texts = contents.map{|html| 
  html
    .gsub(/<!--.*?-->/m, '')
    .gsub(/ /, ' ')
    .gsub(/<\/?[^>]+>/, '') 
}
stop("Strip HTML")

run
texts.map!{|v| v.gsub(/(\s)-{2}(\s)/, '\1-\2')}
stop("Remove `-`")

run
texts.map!{|text| 
  text
    .split("\n")
    .map{|l| l.empty? ? "" : line_to_70(l).join("\n")}
    .join("\n\n").gsub(/\n{4,}/,"\n\n") 
}
stop("Make 70 symbols")

run
texts.each{|v|
    print v
}
stop("To STDOUT")


# Download 2121.023 ms
# Convert to UTF-8 103.808 ms
# Remove \r 60.152 ms
# Strip HTML 331.474 ms
# Remove `-` 102.34 ms
# Make 70 symbols 920.447 ms
# To STDOUT 6.182 ms

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 2)
Ответ на: комментарий от lbvf50txt

Ещё раз, 4 мегабайта это нынче ничто для компьютера. Я сейчас за ноутбуком примерно десятилетней давности, у него экран 2560x1440, это около 14 мегабайт данных (если фреймбуфер 32-битный), и у ноутбука нет проблем 60 раз в секунду эти 14 мегабайт отрисовывать.

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

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

Думаю если переписать без итерации по строкам (мап строку по ньюлайнам же бьёт?), то скорость вообще сравняется.

Вот этого я вообще не понял. Объясните, это как без итерации по строкам?

lbvf50txt
()
Ответ на: комментарий от PolarFox

Зачем применять регексп к куче маленьких кусочков, если можно применить регексп ко всем 4мб сразу?

В коде Regex применяется сразу к всему содержимому одного url. К маленьким кусочкам Regex не применяется.

lbvf50txt
()
Ответ на: комментарий от lbvf50txt

Ну взглядом неправильно незнакомый язык распарсил.

PolarFox ★★★★★
()
Ответ на: комментарий от lbvf50txt

Это задача, которая в одноразовом порядке решается шелл-портянкой.

#!/bin/bash

iconv -f cp1251 -t utf-8 < text_0040.shtml > a1.html
iconv -f cp1251 -t utf-8 < text_0050.shtml > a2.html
iconv -f cp1251 -t utf-8 < text_0060.shtml > a3.html
iconv -f cp1251 -t utf-8 < text_0070.shtml > a4.html

lynx -dump a1.html > a.txt
lynx -dump a2.html >> a.txt
lynx -dump a3.html >> a.txt
lynx -dump a4.html >> a.txt

fold -w 70 -s a.txt > b.txt

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

PolarFox ★★★★★
()
Ответ на: комментарий от PolarFox

Ещё раз, 4 мегабайта это нынче ничто для компьютера.

Хорошее замечание. Как будет расти время от увеличения объема текста?

Для этого я разделил на 100 частей склееный full.html, последовательно 1.txt 1%, 2.txt 2%… 50.txt 50%. И запустил на каждом из них скрипт который читает из STDIN отчищает и пишет в STDOUT. У меня появились от 1.out до 100.out.

Время обработки каждого файла сохранил и построил график. Получилась линейная зависимость O(N).

$ ../generate_input.rb < ../full.html
$ ../test_runner.rb '../solo_convert.rb' > result.txt

Значит на на 400 мегабайтах входных данных программа будет работать примерно в 10 раз дольше чем на 4х. Зависимость линейная, экспоненциального роста нет.

data = [164.85, 151.011, 162.669, 175.017, 201.049, 221.739, 228.004, 239.224, 261.875, 280.373, 300.564, 350.09, 353.148, 377.562, 391.674, 389.741, 390.504, 408.735, 428.344, 448.95, 483.833, 497.628, 523.291, 552.816, 584.088, 587.732, 617.983, 636.114, 654.634, 673.239, 682.929, 705.083, 707.608, 729.104, 755.969, 757.401, 769.343, 852.484, 1072.264, 991.348, 989.184, 945.637, 952.327, 996.974, 1087.463, 1003.792, 1059.615, 1064.336, 1125.961, 1120.822, 1086.853, 1153.689, 1222.432, 1269.17, 1208.205, 1301.069, 1699.173, 1373.679, 1649.239, 1549.224, 1485.164, 1690.101, 1444.22, 1545.653, 1444.16, 1467.775, 1451.028, 1389.065, 1489.893, 1453.532, 1573.752, 1583.63, 1534.204, 1433.793, 1529.9, 1501.916, 1554.593, 1536.611, 1625.377, 1669.558, 1666.085, 2075.091, 2104.185, 1649.098, 1595.364, 1608.449, 1824.89, 1648.908, 1593.274, 1709.72, 1615.083, 1605.355, 1588.183, 1585.656, 1572.336, 1601.225, 1642.869, 1711.62, 1760.258, 1707.271]

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 5)
Ответ на: комментарий от PolarFox

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

При чем тут эта гигантомания? Чуть что сразу «высоконагруженный сервис». До высоко нагруженных сервисов еще много градаций, а много где они вообще не требуются.

Чтоб проверить быстродействие на практической задаче я специально взял огромный пласт текста и не очень заботясь о качестве кода решил прикладную задачу в авральном режиме. И ничего нормально - протискивается в одну секунду. Рабочая тема для ответа на HTTP запрос.

lbvf50txt
()
Ответ на: комментарий от PolarFox

Было бы странно, если у этой программы была бы нелинейная сложность…

Как раз не факт, что там будет линейная сложность так как интенсивно используются Regex. Может быть сложность и не линейная а O(NLogN). Хотя это не суть, прилично работает на 24k строк. Куда уже больше?

lbvf50txt
()
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от PolarFox

именно. на Си пишутся обычно достаточно жирные серверные задачи. хотя я иногда пишу и мелкие одноразовые, если они достаточно сложные и длинные по времени выполнения. недавно понадобилось поправить жирнющий json. там на 15 мегабайт был файлик. простым регекспом не возьмёшь - условие правки было довольно хитрое. вручную можно, но редакторы на таком объёме дико тормозят. и тоже долго колупаться пришлось бы. накалякала сишную программку за 5 минут - всё поправилось моментально. но если можно сделать всё в баше, то нафига расчехлять компилятор?

Iron_Bug ★★★★★
()
Ответ на: комментарий от PolarFox

Мне нравится этот код на Bash. Читабельный, понятный, короткий. Хотелось бы проверить с какой скоростью работает этот Bash script. Но я уже заигрался.

lbvf50txt
()
Ответ на: комментарий от lbvf50txt

На моём примерно 700мсек. Загрузку из интернета убрал за скобки, у кого-то интернет 400мбит, у кого-то 1мбит.

Этот код по большому счёту не на баше, тут вызываются 3 программы, все три, насколько я знаю, на си написаны.

PolarFox ★★★★★
()
Ответ на: комментарий от lbvf50txt

При чем тут эта гигантомания? Чуть что сразу «высоконагруженный сервис»

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

Ещё вижу как за последние пару-тройку десятилетий с одной стороны компьютеры стали в десятки-сотни раз гигагерцовей и гигабайтистей, но при этом всё вокруг тормозит так, как не тормозило на 98й винде на третьем пеньке.

И ничего нормально - протискивается в одну секунду. Рабочая тема для ответа на HTTP запрос.

Это одна секунда одного ядра твоего процессорного времени. Если у сервера 32 ядра, то это около 32 запросов в секунду до того как скорость и этого запроса, и всего остального что происходит на этом сервере начнёт деградировать. Достаточно это или нет? Может быть достаточно, может быть нет. А может это разница между тем платим ли мы 1 у.е., или 2 у.е. за хостинг, а деньги — не бесплатные.

PolarFox ★★★★★
()
Ответ на: комментарий от Iron_Bug

А можно эту задачу опубликовать (в любом удобном формате, хоть описанием)? Если только это не NDA, не вызовет трудностей с вашей стороны и вы не против.

Хочу проверить свой туллинг. Замерами времени и решением поделюсь.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 1)
Ответ на: комментарий от lbvf50txt

а утилита html2text за какое количество времени справилась, не измеряли случаем?

necromant ★★
()
Ответ на: комментарий от kaldeon

какую «задачу»? мне разово надо было поправить поехавший из-за сбоя софтины json. я его поправила. всё. там не было никакой «задачи». выбрать по определённому критерию элементы json'а и заполнить в них данные из другого json'а - это не задача, это просто мелкий скриптик, по сути. можете взять любой json и с ним упражняться сколько хочется.

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

а что обычные «попсовые» текстовые редакторы тормозят на файлах больше мегабайта - это просто факт. хотя мне он непонятен. я когда-то по работе делала редактор бинарных данных, который жевал гигабайты без тормозов. это была вспомогательная утилька для наших задач. просмотр и редактирование крупных raw изображений, с возможностью вручную там что-то поменять. наверное, надо как-то заморочиться и написать текстовый редактор, который нормально работает с отображением больших файлов в память. иногда поправить надо совсем мизер, но из-за размера файла в обычных редакторах это сделать трудно. скорее всего, такие редакторы уже где-нибудь есть, но мне вроде не попадались.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 3)

кстати, пока я тут сидела и среди ночи пила шу-пуэр, почитывая документацию, мне вдруг пришла в голову странная мысль. я думала вообще о другой задаче и там работа со строками отравляла мне весь кайф: текстовые строки медленно форматируются и стрёмно копируются даже в сишке, даже если очень стараться. это никак не улучшить и лучше этого избегать. и тут как раз вылезло это обсуждение про SQL. две мысли наложились друг на друга и мозг сгенерил синтетическую идею: а что, если сделать SQL, но не текстовый, а сразу бинарный? ну, чтобы запросы были бинарные. типа, запрос выглядит как поле с закодированной операцией, далее поля с данными, что-нить а-ля ASN1. и такие же бинарные ответы. а? а может, такое даже уже и есть где-нибудь... бинарный SQL.

надо ещё попить шу-пуэра, пуэр хороший, классический Mэнхай V93. определённо вставляет.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

причём можно сделать обёртку над таким протоколом. два сервера, которые парсят и заворачивают текстовый SQL в бинарный и обмениваются данными по сети. и можно засовывать в любой канал для экономии трафика. а локально по какому-нить unix socket срать в базу, будет очень быстро. или на клиенте сразу вкомпилить реализацию бинарного протокола, а на стороне сервера поставить ретранслятор в текст. наверняка уже кто-то такое сделал. идея простая и красивая. может, даже в самих базах уже где-нибудь реализовано.

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

запрос выглядит как поле с закодированной операцией, далее поля с данными, что-нить а-ля ASN1. и такие же бинарные ответы. а? а может, такое даже уже и есть где-нибудь… бинарный SQL.

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

Над SQL множество обёрток есть на эту тему для различных языков, с конвертацией туда-обратно.

А чтобы полностью сверху донизу — диалект Datalog в Datomic и ему подобных. Про нативную поддержку чего-то подобного в РСУБД не знаю.

Nervous ★★★★★
()
Последнее исправление: Nervous (всего исправлений: 4)
Ответ на: комментарий от Nervous

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

обёртки - это тоже хорошо. только подумаешь - а всё уже реализовано. всё уже написано до нас :)

Iron_Bug ★★★★★
()
Ответ на: комментарий от Iron_Bug

А отлаживать это как?

Ты себе хорошо представляешь типичный вид сложного запроса в СУБД?

Чем хорош SQL: то, что ты человекочитаемо видишь в коде или в логе, то СУБД и исполняет дословно. В случае с бинарным форматом появляется дополнительная прослойка, которая будет тебе это переводить в читаемый вид, что лишняя сущность.

Формирование запроса и его парсинг - это очень малая часть в общей работе СУБД над запросом, и обычно нет никакого смысла это оптимизировать.

Если же сериализация становится узким местом по сравнению с исполнением запроса, то вероятно здесь нужно какое-либо специализированное NOSQL-хранилище, а не реляционная СУБД.

wandrien ★★★
()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от PolarFox

Но зато теперь вместо людей со знанием си, которых, как известно, не существует, нам нужны люди, способные отлаживать и оптимизировать sql-запросы длиной в пару экранов кода.

…и этих людей тоже не существует =)

wandrien ★★★
()
Ответ на: комментарий от wandrien

А отлаживать это как?

как обычно всё отлаживают. в мире, наверное, сотни тысяч, если не миллионы бинарных протоколов. не думаю, что SQL самый сложный из всех. а в чём проблема?

как я писала выше - любая(!) работа со строками - это медленно и печально. даже на чистом Си, даже на ассемблере. это просто очень плохо. если убрать строки - всё должно стать легче и быстрее. причём ускорится не только сеть, но и обработка запросов, логирование и многое другое.

Iron_Bug ★★★★★
()
Последнее исправление: Iron_Bug (всего исправлений: 2)
Ответ на: комментарий от wandrien

а почему бы нет? например, если есть желание засунуть клиент в какой-нибудь мелкий девайс, то запросто. и на стороне сервера убрать парсинг запросов и печать логов с длинными строками было бы просто замечательно. это реально бы ускорило работу.

Iron_Bug ★★★★★
()
Ответ на: комментарий от monk

Так в std::string могут быть любые байты.

А что, если я сделаю собственный аналог, то он магическим образом будет защищен от чтения в него мусора из внешнего файла?

Я же не про std::wstring.

В std::wstring так же могут быть любые байты.

eao197 ★★★★★
()
Ответ на: комментарий от monk

было два телефона контрагента (сделали два поля таблицы)

omg

из трёх вариантов (поле-«массив» -ща json али текст раншее со своим недопарсингом;отдельная табличка {1-n} idU->tel - но да ради двух(не более) это пупка по воробям ; вкорячить в tblU - два поля вместо одного и его велосипедо-парсинга)

выбрали наихудший - ибо 2 номера наворачивает логику - как приотизировать поля какие из 4 вариантов возможно и прочая хурма

ваще это хорошо что процы и память всё дешевле поэтому наниматели могут не заморачиваться с качеством программистов

qulinxao3 ★☆
()
Ответ на: комментарий от eao197

А что, если я сделаю собственный аналог, то он магическим образом будет защищен от чтения в него мусора из внешнего файла?

Почему мусора? В нём будут храниться правильные байты из внешнего файла и в случае хранения через mmap переживать перезапуск программы.

А вот при попытке записать в SQL эти байты могут испортиться… Надо явно указывать, что вот этот std::string в UTF-8, а вон тот может быть с байтами. Унифицированного хранилища std::string в SQL сделать нельзя.

monk ★★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)