
![]() |
Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
|
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.220.216.164] |
![]() |
|
![]() | Данный раздел предназначается для обсуждения вопросов использования баз данных, за исключением составления запросов на SQL. Для этого выделен специальный раздел. Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ. |
Страницы: (4) 1 2 [3] 4 все ( Перейти к последнему сообщению ) |
Сообщ.
#31
,
|
|
|
Вот это не понятно. Как по мне - надо сначала найти урл, если не найден то вставить. Это "тормоз вставки" раз. Потом или повторить поиск или выцепить свежесозданный ид. Это "тормоз вставки" 2 Если окажутся "неуникальные" урлы то данные тормоза возрастут или будут ошибки. Опять же затормозится сильно последующая обработка так как всю эту "неуникальность" придется отдельно анализировать |
![]() |
Сообщ.
#32
,
|
|
Цитата Павел Калугин @ Вот это не понятно. Как по мне - надо сначала найти урл, если не найден то вставить. Это "тормоз вставки" раз. Потом или повторить поиск или выцепить свежесозданный ид. Это "тормоз вставки" 2 Эту проблему решает структура ![]() ![]() CREATE TABLE URLs ( ID integer auto_increment primary key, URL varchar(255), INDEX URL (URL) UNIQUE ); Соответственно просто делаем тупое ![]() ![]() INSERT INTO URLs (URL) VALUES (:url); Если текущий УРЛ отсутствует - вставка выполняется. Если уже присутствует - при выполнении возникает ошибка нарушения уникального индекса, которую мы проигнорируем. Но вне зависимости от того, какой имеется вариант, после выполнения запроса URL в таблице ЕСТЬ. И можно спокойно выполнять ![]() ![]() INSERT INTO clicks(dt, url_id) SELECT now(), id FROM URLs WHERE URLs.URL = :url; |
Сообщ.
#33
,
|
|
|
в таком варианте да.
Интересно было бы смоделировтаь нагрузку, при которой такая вставка "захлебнется" И сровнить с просто записью лога без "разбора на иды".. Но, это наверное после майских можно будет поразвлечься. |
Сообщ.
#34
,
|
|
|
Цитата Akina @ Цитата JoeUser @ Меня смущает запись в логи URL в сыром виде. Туда не URL писать нужно, IdURL, а сам список возможных URL хранить в отдельной таблице. Ну как бы это решение вообще необсуждаемое. Таблица посещений - самая в текущем бизнес-процессе высоконагруженная, следовательно, просто обязана быть максимально компактной. Так что только компактные типы (BIGINT, DATETIME), а всякий текстовый хлам - наружу, и по ссылке. Именно!!! Цитата Павел Калугин @ Интересно было бы смоделировтаь нагрузку, при которой такая вставка "захлебнется" И сровнить с просто записью лога без "разбора на иды".. Но, это наверное после майских можно будет поразвлечься. Павел, а зачем гадать если можно посчитать? ![]() Я вот не поленился и поставил эксперимент. Суть такова: Гипотеза Основное "тонкое" место любой системы, использующей I/O - дисковая подситема - и в первую очередь при простейших счетных операциях. В принципе, это ни разу не гипотеза (для меня, по крайней мере). А не при простейших? Давайте посчитаем плюсы/минусы, да и вообще уместность сбрасывать "нормализованные" логи. Эксперимент При грамотной настройке кэширования движка БД малые таблицы со времени очередного обращения полностью улетают в память, большие таблицы кэшируются частично (скорее всего на уровне индексов). Акей) Пусть аналогом закэшированной таблицы будет структура из STL C++ под названием std::map, считаем та же проиндексированная таблица БД . Для эксперимента собираем и запускаем программу, суть которой в том, что * в первом проходе записываются сырые URL'ы на диск, без каких либо поисков * во втором проходе осуществляется поиск индекса в std::map по URL, который является ключем, а в файл записывается его численное значение из std::map Файлы открываются в режиме бинарного I/O, для работы с файлом выделяется программый буффер в 32 метра. Вот код программы: ![]() ![]() #include <iostream> #include <fstream> #include <random> #include <chrono> #include <map> int main() { // генерируем набор произвольных Url длиной 10-128 символов std::map<std::string,int> ReverseMap; std::vector<std::string> Urls; std::random_device Rd; for (int i=0; i<1000; i++) { std::string S; int Len = Rd() % 118+10; for (int j=0; j<Len; j++) S += (char)('a'+ (Rd() % ('z'-'a'))); std::cout << S << std::endl; Urls.push_back(S); ReverseMap[S] = i; } // генерируем произвольные посещения 1000000 std::vector<int> Get; Get.reserve(1000000); for(int i=0; i<1000000; i++) Get.push_back(Rd() % 1000); char *Buffer = new char[32768*1024]; // записываем "сырые" URL 100000000 шт std::ofstream fs1("test-raw.dat", std::ios::out|std::ios::binary); if (!fs1) { std::cout << "беда-1" << std::endl; delete Buffer; return 1;} fs1.rdbuf()->pubsetbuf(Buffer,32768*1024); auto start = std::chrono::high_resolution_clock::now(); for (int x=0; x<100; x++) for (int i=0; i<1000000; i++) fs1 << Urls[Get[i]]; fs1.flush(); fs1.close(); auto stop = std::chrono::high_resolution_clock::now(); std::cout << "RAW:" << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl; std::cout << std::endl << "Press any key to continue..."; std::cin.get(); // записываем "Id" URL 100000000 шт std::ofstream fs2("test-id.dat", std::ios::out|std::ios::binary); if (!fs2) { std::cout << "беда-1" << std::endl; delete Buffer; return 1;} fs2.rdbuf()->pubsetbuf(Buffer,32768*1024); start = std::chrono::high_resolution_clock::now(); for (int x=0; x<100; x++) for (int i=0; i<1000000; i++) fs2 << ReverseMap[Urls[Get[i]]] << std::endl; fs2.flush(); fs2.close(); stop = std::chrono::high_resolution_clock::now(); std::cout << "ID :" << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl; delete Buffer; return 0; } В результате работы имеем: * Запись "сырых" URL заняла 48566 ms (созданный лог 6.53Gb) * Просчет индексов URL + их запись заняла 185067 ms (созданный лог 0.37 Gb) Скорость записи "сырых" URL почти в 4 раза быстрее (26% от от записи ID). Объем данных, подлежащих записи, для записи по ID в 20 раз меньше (5% от RAW) По скольку скорость итераций ни чем ограничена не была - считаем что запросы обрабатывались во всю дурь мощности компьютера. А если добавить тормоза, обеспечиваемые сетевым обменом? Если без тормозов, то: Обеспечивается запись "сырых" URL: 206180 обращений в секунду Обеспечивается запись "индексов" URL: 54050 обращений в секунду Это все на домашнем компе Intel Core i7, 8Gb ram, FakeRaid (RAID0) 1Tb, Win 8.1 x64 End of гадание на кофейной гуще! ![]() ЗЫ: Бинарник для Win x64 (upx -9) прилагается (VirusTotal.com) Прикреплённый файл ![]() Добавлено ЗЫ: Хотя, сорь, во втором случае в лог попадают не бинарные индексы, а символьные числа. Переделаю, отпишу скорости. |
Сообщ.
#35
,
|
|
|
Теперь с нормализацией получилось даже еще красивше)))
RAW: 50499 ms ID : 23428 ms Как говорится, получите и распишитесь ![]() Просто переделал бинарный вывод. Вот переделанный код. ![]() ![]() #include <iostream> #include <fstream> #include <random> #include <chrono> #include <limits> #include <iomanip> #include <map> int main() { // генерируем набор произвольных Url длиной 10-128 символов std::map<std::string,uint64_t> ReverseMap; std::vector<std::string> Urls; std::random_device Rd; for (int i=0; i<1000; i++) { std::string S; int Len = Rd() % 118+10; for (int j=0; j<Len; j++) S += (char)('a'+ (Rd() % ('z'-'a'))); std::cout << std::setw(6) << i << ": " << S << std::endl; Urls.push_back(S); ReverseMap[S] = i; } // генерируем произвольные посещения 1000000 std::vector<int> Get; Get.reserve(1000000); for(int i=0; i<1000000; i++) Get.push_back(Rd() % 1000); char *Buffer = new char[32768*1024]; // записываем "сырые" URL 10000000 шт std::ofstream fs1("test-raw.dat", std::ios::out|std::ios::binary); if (!fs1) { std::cout << "беда-1" << std::endl; delete Buffer; return 1;} fs1.rdbuf()->pubsetbuf(Buffer,32768*1024); auto start = std::chrono::high_resolution_clock::now(); for (int x=0; x<100; x++) for (int i=0; i<1000000; i++) fs1.write(Urls[Get[i]].c_str(),Urls[Get[i]].length()); fs1.flush(); fs1.close(); auto stop = std::chrono::high_resolution_clock::now(); std::cout << "RAW:" << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl; std::cout << std::endl << "Press any key to continue..."; std::cin.get(); // записываем "Id" URL 10000000 шт std::ofstream fs2("test-id.dat", std::ios::out|std::ios::binary); if (!fs2) { std::cout << "беда-1" << std::endl; delete Buffer; return 1;} fs2.rdbuf()->pubsetbuf(Buffer,32768*1024); start = std::chrono::high_resolution_clock::now(); for (int x=0; x<100; x++) for (int i=0; i<1000000; i++) fs2.write(reinterpret_cast<const char *>(&(ReverseMap[Urls[Get[i]]])), sizeof(uint64_t)); //fs2.write(ReverseMap[Urls[Get[i]]], sizeof(uint64_t)); fs2.flush(); fs2.close(); stop = std::chrono::high_resolution_clock::now(); std::cout << "ID :" << std::chrono::duration_cast<std::chrono::milliseconds>(stop - start).count() << "ms" << std::endl; delete Buffer; return 0; } Бинго! ![]() Прикреплённый файл ![]() |
![]() |
Сообщ.
#36
,
|
|
Цитата JoeUser @ Как говорится, получите и распишитесь Всё это никакого отношения к обсуждаемому выше не имеет. Если очень хочется, то проделай всё то же на любом SQL-сервере. MySQL, FB, MS SQL CE... неважно, каком. Сгенери таблицу на, скажем, 1кк URL, а потом замерь время вставки 10к записей, из которых 9к дубли, по первой и по второй технологии. Такой эксперимент будет хоть как-то адекватен, особенно если сможешь организовать многопоточную вставку. |
Сообщ.
#37
,
|
|
|
Цитата Akina @ Сгенери таблицу на, скажем, 1кк URL Э неее ... На сайте, коль регистрируется доступ к ресурсам, от силы 1к своих URL, и то это черезчур. Нам надо сделать таблицу 1к URL и сымитировать доступ к ним, с записью лога "сырого" и "нормализованного". В своей тестовой программе я лишь заценил возможный пересчет перед записью (на сколько пересчет будет трудоемким). Не думаю, что авторы полнотекстового поиска в БД тупее реализаторов такого же поиска в std::map. А на счет предложенного тобою теста - боюсь он буден неадекватен, ибо у меня все БД сервера (PostgreSQL и MySQL) запущены под виртуальными машинами, а виртуализация вносит хаос в тесты, уже не раз проверено. Разные запуски одного и того же могут давать результаты вплоть до обратного. Хотя можно попробовать. Подумаю |
![]() |
Сообщ.
#38
,
|
|
Цитата JoeUser @ На сайте, коль регистрируется доступ к ресурсам, от силы 1к своих URL, и то это черезчур. Нам надо сделать таблицу 1к URL и сымитировать доступ к ним, с записью лога "сырого" и "нормализованного". Я имел в виду 1кк уже существующих записей лога, а не уникальных URL. Впрочем, согласен, что 10к уников - многовато. |
Сообщ.
#39
,
|
|
|
Цитата Akina @ Такой эксперимент будет хоть как-то адекватен, особенно если сможешь организовать многопоточную вставку. Вощем заинтересовался и сделал. Генерируется 10 нитей (threads), каждая нить параллельно пишет лог в БД по 100000 записей. Увы, БД крутится под FreeBSD 9.0, которая запущена под VMWare - отсюда точность хреновенькая. Вот код: ![]() ![]() #!/usr/bin/perl -w # Подключаем библиотеки use Time::HiRes qw(gettimeofday); use threads; use threads::shared; use DBI; # список создаваемых URL @URLs = (); @Req = (); # реквизиты БД $DBName = "testo"; $UserName = "pgsql"; $DBHost = "192.168.1.47"; $DBPort = "5432"; # счетчики замеров $TimeRaw = 0; $TimeId = 0; $SizeRaw = 0; $SizeId = 0; ############################################################################### $|++; if ($^O =~ /win/i) { system("cls"); } else { system("clear"); } print "\nПоехали тестировать ============================================\n\n"; ############################################################################### # 1.Генерируем 1000 URL'ов произвольной длины в диапазоне 12...255 GenerateUrls(\@URLs); # 2.Гененируем таблицу запросов (индексы из @URLs) GenerateReq(\@Req); # 3.Чистим таблицы и записываем "каталог" URLs в БД PrepareTables(\@URLs); # 4.Запускаем 10 потоков за запись "сырых" логов и засекаем время их исполнения ThreadRawFunc(); # 5.Вызываем вакуум и вычисляем размер полученной таблицы LogsRaw $SizeRaw = GatheringStats("LogsRaw"); # 6.Чистим таблицы и записываем "каталог" URLs в БД PrepareTables(\@URLs); # 7.Запускаем 10 потоков за запись "нормализованных" логов ThreadIdFunc(); # 8.Вызываем вакуум и вычисляем размер полученной таблицы LogsId $SizeId = GatheringStats("LogsId"); # 9.Отчет print "\n Время записи RAW-логов: $TimeRaw сек (полученный размер: $SizeRaw Mb)\n Время записи \"нормализованных\"-логов: $TimeId сек (полученный размер: $SizeId Mb)\n\n"; ############################################################################### sub GenerateUrls { print " * Генерируем URL'ы ... "; my $Array = shift; srand(); for my $I (1..1000) { my $S = ""; for my $J (0..rand(244)+11) { $S .= chr(ord('a')+rand(ord('z')-ord('a'))); } push @{$Array}, $S; } print "Ok\n"; } sub GenerateReq { print " * Генерируем произвольный массив индексов запросов URLs ... "; my $Array = shift; srand(); for my $I (1..100000) { push @{$Array}, int(rand(999)); } print "Ok\n"; } sub PrepareTables { my $Array = shift; my $Dbh = DBI->connect("dbi:Pg:dbname=$DBName;host=$DBHost;port=$DBPort","$UserName","",{PrintError => 0}); die "$DBI::errstr\n" if (defined($DBI::err)); # -- чистим таблицу URL print "\n * Подготавливаем БД:\n"; print " - чистим таблицу URLs ... "; my $query = "DELETE FROM \"URLs\""; my $sth = $Dbh->prepare($query); my $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- чистим таблицу LogsRaw print " - чистим таблицу LogRaw ... "; $query = "DELETE FROM \"LogsRaw\""; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- чистим таблицу LogsId print " - чистим таблицу LogId ... "; $query = "DELETE FROM \"LogsId\""; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- сбрасываем счетчики Id таблиц print " - сбрасываем счетчики Id таблиц ... "; $query = "ALTER SEQUENCE public.\"URLs_Id_seq\" INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 RESTART 1 CACHE 1 NO CYCLE"; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); $query = "ALTER SEQUENCE public.\"LogsId_Id_seq\" INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 RESTART 1 CACHE 1 NO CYCLE"; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); $query = "ALTER SEQUENCE public.\"Logs_Id_seq\" INCREMENT 1 MINVALUE 1 MAXVALUE 9223372036854775807 START 1 RESTART 1 CACHE 1 NO CYCLE"; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- вакуум print " - вакуум + сбор статистики ... "; $query = "VACUUM FULL ANALYZE"; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- заполняем таблицу URLs print " - запоняем таблицу URLs ... "; $query = "INSERT INTO \"URLs\" (\"URL\") VALUES "; for(my $I=0; $I<scalar(@{$Array}); $I++) { $query.="('".${$Array}[$I]."')"; $query.= ", " if ($I+1<scalar(@{$Array})); } $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); print "Ok\n"; # -- переиндексируем таблицу URL print " - переиндексируем таблицу URLs ... "; $query = "REINDEX TABLE \"URLs\""; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); $Dbh->disconnect(); print "Ок\n - пауза 30 сек ... "; sleep(30); print "Ok\n\n"; } sub ThreadRawFunc { print " * Записываем LogsRaw "; my @Threads; my $Threads=10; # Создаём нужное количество потоков for my $T (1..$Threads) { push @Threads, threads->create(\&WriteLogsRaw, $T); } # Дожидаемся окончания работы всех потоков my $Start = gettimeofday; foreach my $T (@Threads) { $T->join(); } $TimeRaw = gettimeofday() - $Start; print " Ok\n"; } sub ThreadIdFunc { print " * Записываем LogsId "; my @Threads; my $Threads=10; # Создаём нужное количество потоков for my $T (1..$Threads) { push @Threads, threads->create(\&WriteLogsId, $T); } # Дожидаемся окончания работы всех потоков my $Start = gettimeofday; foreach my $T (@Threads) { $T->join(); } $TimeId = gettimeofday() - $Start; print " Ok\n"; } sub WriteLogsRaw { print "."; my $Dbh = DBI->connect("dbi:Pg:dbname=$DBName;host=$DBHost;port=$DBPort","$UserName","",{PrintError => 0}); die "$DBI::errstr\n" if (defined($DBI::err)); foreach my $I (@{Req}) { my $query = "INSERT INTO \"LogsRaw\" (\"URL\",\"Timestamp\") VALUES ('".$URLs[$I]."', NOW())"; my $sth = $Dbh->prepare($query); my $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); } $Dbh->disconnect(); } sub WriteLogsId { print "."; my $Dbh = DBI->connect("dbi:Pg:dbname=$DBName;host=$DBHost;port=$DBPort","$UserName","",{PrintError => 0}); die "$DBI::errstr\n" if (defined($DBI::err)); foreach my $I (@{Req}) { my $query = "INSERT INTO \"LogsId\" (\"IdUrl\",\"Timestamp\") VALUES ((SELECT u.\"Id\" FROM \"URLs\" AS u WHERE u.\"URL\" = '".$URLs[$I]."'), NOW())"; my $sth = $Dbh->prepare($query); my $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); } $Dbh->disconnect(); } sub GatheringStats { my $Name = shift; print " * Поизводим вакуум и вычисляем размер таблицы \"".$Name."\" ... "; my $Dbh = DBI->connect("dbi:Pg:dbname=$DBName;host=$DBHost;port=$DBPort","$UserName","",{PrintError => 0}); die "$DBI::errstr\n" if (defined($DBI::err)); my $query = "VACUUM FULL ANALYZE"; my $sth = $Dbh->prepare($query); my $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); $query = "SELECT (relpages * 8192 / (1024*1024))::int as size_mb FROM pg_class WHERE relname LIKE '".$Name."'"; $sth = $Dbh->prepare($query); $rv = $sth->execute(); die "Error query on \"$query\": " . $Dbh->errstr . "\n" unless(defined $rv); my @array = $sth->fetchrow_array(); $sth->finish(); $Dbh->disconnect(); print " Ok\n"; return $array[0]; } Вот результаты: ![]() ![]() Поехали тестировать ============================================ * Генерируем URL'ы ... Ok * Генерируем произвольный массив индексов запросов URLs ... Ok * Подготавливаем БД: - чистим таблицу URLs ... Ok - чистим таблицу LogRaw ... Ok - чистим таблицу LogId ... Ok - сбрасываем счетчики Id таблиц ... Ok - вакуум + сбор статистики ... Ok - запоняем таблицу URLs ... Ok - переиндексируем таблицу URLs ... Ок - пауза 30 сек ... Ok * Записываем LogsRaw .......... Ok * Поизводим вакуум и вычисляем размер таблицы "LogsRaw" ... Ok * Подготавливаем БД: - чистим таблицу URLs ... Ok - чистим таблицу LogRaw ... Ok - чистим таблицу LogId ... Ok - сбрасываем счетчики Id таблиц ... Ok - вакуум + сбор статистики ... Ok - запоняем таблицу URLs ... Ok - переиндексируем таблицу URLs ... Ок - пауза 30 сек ... Ok * Записываем LogsId .......... Ok * Поизводим вакуум и вычисляем размер таблицы "LogsId" ... Ok Время записи RAW-логов: 312.937685012817 сек (полученный размер: 176 Mb) Время записи "нормализованных"-логов: 391.566915035248 сек (полученный размер: 45 Mb) Запускал несколько раз, заметил закономерность - чем больше итераций в нити, тем ближе время записи "нормализованного" лога к "сырому". На итерациях порядка 1000 разница была чуть ли не в треть. Больше ждать лениво, да и как говорил - виртуализация портит точность. А на живом железе запустить нет возможности. Тем не менее ... худший результат ("нормализованная" запись логов) дает нам скорость 2557 записи/сек. Для таких условий, как проводилось тестирование, я считаю результат вполне приемлем. |
![]() |
Сообщ.
#40
,
|
|
У меня с перлом не сложилось... но, насколько я понял, ты замеряешь время загрузки большого массива в пустые таблицы. Если так - это неверно. Надо мерить время загрузки сравнительно небольшой порции (скажем, 10 тыс.) в заполненную большим количеством (скажем, 1 млн.) записей структуру.
|
Сообщ.
#41
,
|
|
|
Цитата Akina @ но, насколько я понял, ты замеряешь время загрузки большого массива в пустые таблицы. Да, сперва чистка, потом вакуум, потом загрузка. Цитата Akina @ Надо мерить время загрузки сравнительно небольшой порции (скажем, 10 тыс.) в заполненную большим количеством (скажем, 1 млн.) записей структуру. Попробую вечером посмотреть че можно сделать. Дело в том, что у меня в виртуальных машинах свободного дискового пространства по минимуму - оттого и не могу грузить много. Надо проинспектировать ) Есть еще 4 VM под управлением разных версий линухов, и одна - под Mac OS X. Может быть там есть место, просто не помню. |
Сообщ.
#42
,
|
|
|
Тест крайне простой
- "нагрузка" нужна не с 10 а, хотябы со 100 и не нитей а приложений. - тест 1 выполняется "инсерт" в таблицу - тест 2 выполняется "нормализация" с поиском и вставкой если не нашли - тест 3 выполняется "инсерт" с "подавлением ошибки" и последующим поиском Тестовое приложение умеет принять код "теста" 1,2,3, принять параметр "кол-во запущенных", задержку до начала теста начать отсчет времени,выполнтить тест, завершить отсчет положить в лог тест, кол-во запросов, время на исволнение "Пускалка" должна принять номер теста, кол-во "запросов" в тесте, количество стартов, подготовить данные и запустить заданное количество "тестов" Задержка нужна чтобы все тесты стартовали +- одновременно Вот над таким собираюсь на вторые майские посидеть. Сейчас времени нет, удочки собираю ![]() |
Сообщ.
#43
,
|
|
|
Цитата Павел Калугин @ Вот над таким собираюсь на вторые майские посидеть. Если у тя есть реальный железный сервак БД (выделенный) - имеет смысл заморачиваться, ибо результаты будут более правдивы, чем у меня с ВМ. Цитата Павел Калугин @ и не нитей а приложений Вот тут не согласен. Для движка БД абсолютно фиолетово от кого ловить соединение. А вот на клиенте накладных расходов (в случае нитей) будет гораздо меньше, что даст большую чистоту теста. Мы же пытаемся имитировать одно соединение с 10..100 компьютеров. Нам накладные расходы по управлению процессами не нужны ни разу. Добавлено Цитата Павел Калугин @ - тест 2 выполняется "нормализация" с поиском и вставкой если не нашли И тут момент. ИМХО, вставка URL в свой "каталог URLs" нужно делать в момент создания "материала" (будь то статическая страница, будь то динамическая тема форума, к примеру). А именно поиск+вставка прокатит, если мы хотим собрать статистику по ошибочным обращениям. |
Сообщ.
#44
,
|
|
|
Цитата JoeUser @ Если у тя есть реальный железный сервак БД (выделенный) - имеет смысл заморачиваться, ибо результаты будут более правдивы, чем у меня с ВМ. есть, но он стаааренький ![]() Примерно как буду делать - возьму живой лог со своих сайтов, догененрю до разумного числа обращений , запихаю в "массив строк" и ... буду вливать его построчно соответственно с трех - четырех - пяти компуков можно будет прогнать каку. Но тут сразу погрешности будут на "шнурки". |
Сообщ.
#45
,
|
|
|
Цитата Павел Калугин @ буду вливать его построчно Кстати, ознакомься с этой темой. Есть предположение что, если грамотно реализовать сборку единичных логов в "пакеты", то можно будет выжимать чудеса по скоростям ![]() |