На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! информация о разделе
user posted imageДанный раздел предназначается для обсуждения вопросов использования баз данных, за исключением составления запросов на SQL. Для этого выделен специальный раздел. Убедительная просьба - соблюдать "Правила форума" и не пренебрегать "Правильным оформлением своих тем". Прежде, чем создавать тему, имеет смысл заглянуть в раздел "Базы данных: FAQ", возможно там уже есть ответ.

Модераторы: Chow, Bas, MIF
Страницы: (4) 1 2 [3] 4  все  ( Перейти к последнему сообщению )  
> Проблема сортировки по разнице изменения числа
    Цитата Akina @
    ошибку дублирования злостно игнорируем

    Вот это не понятно. Как по мне - надо сначала найти урл, если не найден то вставить. Это "тормоз вставки" раз. Потом или повторить поиск или выцепить свежесозданный ид. Это "тормоз вставки" 2
    Если окажутся "неуникальные" урлы то данные тормоза возрастут или будут ошибки. Опять же затормозится сильно последующая обработка так как всю эту "неуникальность" придется отдельно анализировать
      Цитата Павел Калугин @
      Вот это не понятно. Как по мне - надо сначала найти урл, если не найден то вставить. Это "тормоз вставки" раз. Потом или повторить поиск или выцепить свежесозданный ид. Это "тормоз вставки" 2

      Эту проблему решает структура
      ExpandedWrap disabled
        CREATE TABLE URLs (
            ID integer auto_increment primary key,
            URL varchar(255),
            INDEX URL (URL) UNIQUE
        );

      Соответственно просто делаем тупое
      ExpandedWrap disabled
        INSERT INTO URLs (URL) VALUES (:url);

      Если текущий УРЛ отсутствует - вставка выполняется. Если уже присутствует - при выполнении возникает ошибка нарушения уникального индекса, которую мы проигнорируем. Но вне зависимости от того, какой имеется вариант, после выполнения запроса URL в таблице ЕСТЬ. И можно спокойно выполнять
      ExpandedWrap disabled
        INSERT INTO clicks(dt, url_id)
        SELECT now(), id
        FROM URLs
        WHERE URLs.URL = :url;
        в таком варианте да.
        Интересно было бы смоделировтаь нагрузку, при которой такая вставка "захлебнется"
        И сровнить с просто записью лога без "разбора на иды".. Но, это наверное после майских можно будет поразвлечься.
          Цитата Akina @
          Цитата JoeUser @
          Меня смущает запись в логи URL в сыром виде. Туда не URL писать нужно, IdURL, а сам список возможных URL хранить в отдельной таблице.

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

          Именно!!!

          Цитата Павел Калугин @
          JoeUser Как верно Акина написал выше - гадание на кофейной гуще.

          Цитата Павел Калугин @
          Интересно было бы смоделировтаь нагрузку, при которой такая вставка "захлебнется"
          И сровнить с просто записью лога без "разбора на иды".. Но, это наверное после майских можно будет поразвлечься.


          Павел, а зачем гадать если можно посчитать? :lol:

          Я вот не поленился и поставил эксперимент. Суть такова:

          Гипотеза

          Основное "тонкое" место любой системы, использующей I/O - дисковая подситема - и в первую очередь при простейших счетных операциях. В принципе, это ни разу не гипотеза (для меня, по крайней мере). А не при простейших? Давайте посчитаем плюсы/минусы, да и вообще уместность сбрасывать "нормализованные" логи.

          Эксперимент

          При грамотной настройке кэширования движка БД малые таблицы со времени очередного обращения полностью улетают в память, большие таблицы кэшируются частично (скорее всего на уровне индексов). Акей) Пусть аналогом закэшированной таблицы будет структура из STL C++ под названием std::map, считаем та же проиндексированная таблица БД . Для эксперимента собираем и запускаем программу, суть которой в том, что

          * в первом проходе записываются сырые URL'ы на диск, без каких либо поисков
          * во втором проходе осуществляется поиск индекса в std::map по URL, который является ключем, а в файл записывается его численное значение из std::map

          Файлы открываются в режиме бинарного I/O, для работы с файлом выделяется программый буффер в 32 метра.

          Вот код программы:

          ExpandedWrap disabled
            #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 гадание на кофейной гуще! :thanks:

          ЗЫ: Бинарник для Win x64 (upx -9) прилагается (VirusTotal.com)


          Прикреплённый файлПрикреплённый файлTestNormalisation.exe.7z (242,19 Кбайт, скачиваний: 161)

          Добавлено
          ЗЫ: Хотя, сорь, во втором случае в лог попадают не бинарные индексы, а символьные числа. Переделаю, отпишу скорости.
            Теперь с нормализацией получилось даже еще красивше)))

            RAW: 50499 ms
            ID : 23428 ms

            Как говорится, получите и распишитесь :lol: Правда второй лог вырос до 0.76Gb, но не суть!

            Просто переделал бинарный вывод. Вот переделанный код.

            ExpandedWrap disabled
              #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;
              }


            Бинго! :lool:
            Прикреплённый файлПрикреплённый файлTestNormalisation_2.exe.7z (210,5 Кбайт, скачиваний: 142)
              Цитата JoeUser @
              Как говорится, получите и распишитесь

              Всё это никакого отношения к обсуждаемому выше не имеет.
              Если очень хочется, то проделай всё то же на любом SQL-сервере. MySQL, FB, MS SQL CE... неважно, каком. Сгенери таблицу на, скажем, 1кк URL, а потом замерь время вставки 10к записей, из которых 9к дубли, по первой и по второй технологии. Такой эксперимент будет хоть как-то адекватен, особенно если сможешь организовать многопоточную вставку.
                Цитата Akina @
                Сгенери таблицу на, скажем, 1кк URL


                Э неее ... На сайте, коль регистрируется доступ к ресурсам, от силы 1к своих URL, и то это черезчур. Нам надо сделать таблицу 1к URL и сымитировать доступ к ним, с записью лога "сырого" и "нормализованного". В своей тестовой программе я лишь заценил возможный пересчет перед записью (на сколько пересчет будет трудоемким). Не думаю, что авторы полнотекстового поиска в БД тупее реализаторов такого же поиска в std::map.

                А на счет предложенного тобою теста - боюсь он буден неадекватен, ибо у меня все БД сервера (PostgreSQL и MySQL) запущены под виртуальными машинами, а виртуализация вносит хаос в тесты, уже не раз проверено. Разные запуски одного и того же могут давать результаты вплоть до обратного.

                Хотя можно попробовать. Подумаю
                  Цитата JoeUser @
                  На сайте, коль регистрируется доступ к ресурсам, от силы 1к своих URL, и то это черезчур. Нам надо сделать таблицу 1к URL и сымитировать доступ к ним, с записью лога "сырого" и "нормализованного".

                  Я имел в виду 1кк уже существующих записей лога, а не уникальных URL. Впрочем, согласен, что 10к уников - многовато.
                    Цитата Akina @
                    Такой эксперимент будет хоть как-то адекватен, особенно если сможешь организовать многопоточную вставку.

                    Вощем заинтересовался и сделал. Генерируется 10 нитей (threads), каждая нить параллельно пишет лог в БД по 100000 записей. Увы, БД крутится под FreeBSD 9.0, которая запущена под VMWare - отсюда точность хреновенькая.

                    Вот код:

                    ExpandedWrap disabled
                      #!/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];
                      }


                    Вот результаты:

                    ExpandedWrap disabled
                      Поехали тестировать ============================================
                       
                       * Генерируем 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 записи/сек. Для таких условий, как проводилось тестирование, я считаю результат вполне приемлем.
                      У меня с перлом не сложилось... но, насколько я понял, ты замеряешь время загрузки большого массива в пустые таблицы. Если так - это неверно. Надо мерить время загрузки сравнительно небольшой порции (скажем, 10 тыс.) в заполненную большим количеством (скажем, 1 млн.) записей структуру.
                        Цитата Akina @
                        но, насколько я понял, ты замеряешь время загрузки большого массива в пустые таблицы.

                        Да, сперва чистка, потом вакуум, потом загрузка.

                        Цитата Akina @
                        Надо мерить время загрузки сравнительно небольшой порции (скажем, 10 тыс.) в заполненную большим количеством (скажем, 1 млн.) записей структуру.

                        Попробую вечером посмотреть че можно сделать. Дело в том, что у меня в виртуальных машинах свободного дискового пространства по минимуму - оттого и не могу грузить много. Надо проинспектировать ) Есть еще 4 VM под управлением разных версий линухов, и одна - под Mac OS X. Может быть там есть место, просто не помню.
                          Тест крайне простой
                          - "нагрузка" нужна не с 10 а, хотябы со 100 и не нитей а приложений.
                          - тест 1 выполняется "инсерт" в таблицу
                          - тест 2 выполняется "нормализация" с поиском и вставкой если не нашли
                          - тест 3 выполняется "инсерт" с "подавлением ошибки" и последующим поиском

                          Тестовое приложение умеет принять код "теста" 1,2,3, принять параметр "кол-во запущенных", задержку до начала теста начать отсчет времени,выполнтить тест, завершить отсчет положить в лог тест, кол-во запросов, время на исволнение
                          "Пускалка" должна принять номер теста, кол-во "запросов" в тесте, количество стартов, подготовить данные и запустить заданное количество "тестов"
                          Задержка нужна чтобы все тесты стартовали +- одновременно

                          Вот над таким собираюсь на вторые майские посидеть.
                          Сейчас времени нет, удочки собираю :)
                            Цитата Павел Калугин @
                            Вот над таким собираюсь на вторые майские посидеть.

                            Если у тя есть реальный железный сервак БД (выделенный) - имеет смысл заморачиваться, ибо результаты будут более правдивы, чем у меня с ВМ.

                            Цитата Павел Калугин @
                            и не нитей а приложений

                            Вот тут не согласен. Для движка БД абсолютно фиолетово от кого ловить соединение. А вот на клиенте накладных расходов (в случае нитей) будет гораздо меньше, что даст большую чистоту теста. Мы же пытаемся имитировать одно соединение с 10..100 компьютеров. Нам накладные расходы по управлению процессами не нужны ни разу.

                            Добавлено
                            Цитата Павел Калугин @
                            - тест 2 выполняется "нормализация" с поиском и вставкой если не нашли

                            И тут момент. ИМХО, вставка URL в свой "каталог URLs" нужно делать в момент создания "материала" (будь то статическая страница, будь то динамическая тема форума, к примеру). А именно поиск+вставка прокатит, если мы хотим собрать статистику по ошибочным обращениям.
                              Цитата JoeUser @
                              Если у тя есть реальный железный сервак БД (выделенный) - имеет смысл заморачиваться, ибо результаты будут более правдивы, чем у меня с ВМ.

                              есть, но он стаааренький :)
                              Примерно как буду делать - возьму живой лог со своих сайтов, догененрю до разумного числа обращений , запихаю в "массив строк" и ... буду вливать его построчно
                              соответственно с трех - четырех - пяти компуков можно будет прогнать каку. Но тут сразу погрешности будут на "шнурки".
                                Цитата Павел Калугин @
                                буду вливать его построчно

                                Кстати, ознакомься с этой темой.
                                Есть предположение что, если грамотно реализовать сборку единичных логов в "пакеты", то можно будет выжимать чудеса по скоростям :)
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (4) 1 2 [3] 4  все


                                Рейтинг@Mail.ru
                                [ Script execution time: 0,0688 ]   [ 19 queries used ]   [ Generated: 29.03.24, 14:08 GMT ]