Apache Ignite против производительности SQL Server - PullRequest
0 голосов
/ 17 марта 2019

Мы рассматриваем возможность использования базы данных In-Memory (например, Apache Ignite) для выполнения интенсивных BI-подобных операций.В качестве (очень примитивного) примера я заполнил Apache Ignite 250 000 записей из csv-файла (14 столбцов) и выполнил некоторые операции группировки.Ранее я также использовал те же данные для некоторых тестов производительности с MS SQL-сервером.

Интересно и неожиданно, чтобы MS SQL-Server потребовалось около 0,25 секунды для выполнения этих операций, в то время как с Apache Ignite это занимает 1-2 секунды.

1, у меня всегда было впечатление, что Apache Ignite - это не только хороший вариант для распределенных вычислений, но также приводит к увеличению производительности по сравнению с обычной реляционной базой данных благодаря своей архитектуре, ориентированной на память.Это правда?Почему это медленно в моем примере?

2, я неправильно использовал Apache Ignite или есть какие-то дополнительные параметры настройки, которые мне следует использовать?

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

  private static Connection conn = null;
  private static Statement stmt = null;
  private static ResultSet rs = null;

  private static void initialize() throws ClassNotFoundException, SQLException

  {

       // Register JDBC driver.
    Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

    // Create database tables.
    stmt = conn.createStatement();

    // Create table
    stmt.executeUpdate("CREATE TABLE PIVOT_TEST (" +
    " REGION VARCHAR, COUNTRY VARCHAR, ITEM_TYPE VARCHAR, SALES_CHANNEL VARCHAR, ORDER_PRIORITY VARCHAR, ORDER_DATE VARCHAR, ORDER_ID VARCHAR PRIMARY KEY, "
    + "SHIP_DATE VARCHAR, UNITS_SOLD NUMERIC, UNIT_PRICE NUMERIC, UNIT_COST NUMERIC, TOTAL_REVENUE NUMERIC, TOTAL_COST NUMERIC, TOTAL_PROFIT NUMERIC )");

  }



  private static void fill() throws ClassNotFoundException, SQLException
  {
        // Register JDBC driver
        Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

        // Populate table
        PreparedStatement stmt =
        conn.prepareStatement("COPY FROM 'LINK_TO_CSV_FILE'" +

        "INTO PIVOT_TEST (REGION , COUNTRY , ITEM_TYPE , SALES_CHANNEL , ORDER_PRIORITY , ORDER_DATE , ORDER_ID , SHIP_DATE , UNITS_SOLD , UNIT_PRICE , UNIT_COST , TOTAL_REVENUE , TOTAL_COST , TOTAL_PROFIT ) FORMAT CSV");
        stmt.executeUpdate();

        stmt = conn.prepareStatement("CREATE INDEX index_name ON PIVOT_TEST(COUNTRY)");
        stmt.executeUpdate();
  }



  private static void getResult() throws ClassNotFoundException, SQLException
  {
        // Register JDBC driver
        Class.forName("org.apache.ignite.IgniteJdbcThinDriver");

        // Get data
        stmt = conn.createStatement();

        rs =
            stmt.executeQuery("SELECT AVG(UNIT_PRICE) AS AVG_UNIT_PRICE, MAX(UNITS_SOLD) AS MAX_UNITS_SOLD, SUM(UNIT_COST) AS SUM_UNIT_COST, AVG(TOTAL_REVENUE) AS AVG_TOTAL_REVENUE , AVG(TOTAL_COST) AS AVG_TOTAL_COST, AVG(TOTAL_PROFIT) as AVG_TOTAL_PROFIT  FROM PIVOT_TEST GROUP BY COUNTRY;");

        retrieveResultSet();      

  }



  private static void retrieveResultSet() throws SQLException
  {
        while (rs.next())
        {
                for(int i=0; i<rs.getMetaData().getColumnCount(); i++)
                {
                    rs.getObject(i+1);
                }
        }
  }



  public static void main(String[] args) throws SQLException, ClassNotFoundException

  {

        Ignite ignite = null;

        try

        {

            //--------------------------------CONNECTION-------------------//

            IgniteConfiguration configuration = new IgniteConfiguration();

            ignite = Ignition.start(configuration);

            conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1/");

            initialize();

            fill();


            long endPrepTable = System.currentTimeMillis();

            getResult();

            long endGetResult = System.currentTimeMillis();

            System.out.println("Get Result (s)" + " " + (endGetResult - endPrepTable)*1.0/1000);

        }

        catch(Exception e)
        {
            e.printStackTrace();
        }

        finally
        {
          ignite.close();

          conn.close();

          rs.close();
        }

  }

Спасибо за вашу помощь!

Ответы [ 3 ]

0 голосов
/ 18 марта 2019

Как и в любой базе данных, существует множество способов ее настройки и оптимизации. И Ignite разработан с другими компромиссами, чем SQL Server - невозможно гарантировать , что это будет быстрее в каждом случае.

Сказав это, есть некоторая документация по улучшению производительности .

На что следует обратить внимание: четверть миллиона записей не так много. Ignite оптимизирован для работы в кластере, где операции могут распараллеливаться. С одним «сложным» запросом вам может потребоваться увеличить queryParallelism, иначе вы будете ограничены одним потоком в каждом узле.

Конечно, вы также можете сделать что-то вроде EXPLAIN PLAN, чтобы убедиться, что он использует правильные индексы и т. Д. Как и в любом упражнении по оптимизации, это столько же искусство, сколько наука.

0 голосов
/ 19 марта 2019

При сравнении Ignite с реляционной базой данных следует учитывать несколько моментов:

  • Механизм SQL Ignite оптимизирован для развертывания нескольких узлов с ОЗУ в качестве основного хранилища.Не пытайтесь сравнивать одноузловой кластер Ignite с реляционной базой данных, которая была оптимизирована для таких конфигураций.Разверните многоузловой кластер с полной копией данных в ОЗУ.
  • Примите во внимание основные рекомендации при моделировании данных и оптимизации, такие как сопоставление сродства, вторичные индексы и другие , перечисленные здесь .
  • Кроме того, имейте в виду, что реляционные базы данных используют методы локального кэширования и зависят от общего размера данных, а тип запроса может выполнять некоторые запросы даже быстрее, чем Ignite в конфигурации с несколькими узлами.Например, я видел SQL-сервер, выполняющий запрос ниже в течение 5 мс, в то время как Ignite кластер с одним узлом за 8 мс и кластер с 4 узлами за 20 мс:

    SELECT * FROM Input i JOIN Party pr ON (pr.prt_id) = (i.mbr_id) порядок по i.input_id смещение 0 предел 100

    Ожидалось, потому что размер набора данных был около 64 ГБ, и SQL Server мог кэшировать много в локальной оперативной памяти.Кроме того, затраты на внутриузловую связь повлияли на число кластеров из 4 узлов по сравнению с одним узлом.

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

    SELECT * FROM Input i INNER JOIN Product p ON (i.product_id) = (p.product_id) INNER JOIN Party pr ON(pr.prt_id) = (i.mbr_id) и (pr.session_id = i.session_id) WHERE I.PRODUCT_ID = 5 и I.SOURCE_ID = 6

    В моем случае для SQL Server потребовалось 510 секундв той же конфигурации и 64 ГБ данных для завершения запроса (он должен был идти на диск).Кластер из 4 узлов Ignite завершился за 32 секунды, а кластер из 8 узлов - за 8 секунд.

0 голосов
/ 18 марта 2019

Вы можете применить следующие точки поворота:

  1. Использовать совместно расположенный флаг [1]:

    jdbc: ignite: thin: //127.0.0.1; совместно расположенный= true

  2. Введите переменную для rs.getMetaData (). getColumnCount ():

    int count = rs.getMetaData (). getColumnCount ();while (rs.next ()) {for (int i = 0; i

[1] https://apacheignite -sql.readme.io / docs / jdbc-driver # section-параметры

[2]https://apacheignite.readme.io/docs/affinity-collocation#collocate-data-with-data

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...