Статьи

Основное использование для первичного индекса Couchbase

 FROM customer USE KEYS ["cx:123"] Couchbase — это распределенная база данных. Он поддерживает гибкую модель данных с использованием JSON . Каждый документ в корзине будет иметь сгенерированный пользователем уникальный ключ документа. Эта уникальность обеспечивается во время вставки или обновления данных. Вот пример документа.

select meta().id, travel
from `travel-sample` travel
where type = 'airline' limit 1;
[
  {
      "id": "airline_10",
      "travel": {
          "callsign": "MILE-AIR",
          "country": "United States",
          "iata": "Q5",
          "icao": "MLA",
          "id": 10,
          "name": "40-Mile Air",
          "type": "airline"
          }
      }
  ]



INSERT INTO customer (key, value) VALUES(“cx:123”, {“name”:”joe”, “zip”: 94040, “state”:ca});

SELECT META().id FROM customer;

cx:123

Каждое хранилище Couchbase может хранить данные в нескольких типах: клиент, заказ, каталог и т. Д. Когда вы загружаете набор данных «travel-sample», вы загружаете пять различных типов документов: авиакомпания, аэропорт, гостиница, маршрут и ориентиры.

Но по умолчанию Couchbase не имеет эквивалента « полного сканирования таблицы » для сканирования всех документов от начала до конца. Сканирование основного индекса обеспечивает эквивалент «полного сканирования таблицы».

Вам также может понравиться: Все, что вам нужно знать об архитектуре Couchbase .

 CREATE PRIMARY INDEX ix_customer_primary ON customer; 

Основной индекс:

  • Сортированный список всех ключей документов каждого типа документа в пределах группы клиентов.
  • Поддерживается асинхронно, как и другие вторичные индексы.
  • Хранит только ключ документа и больше ничего.
  • Поддерживает все последовательности сканирования:

    • Неограниченные.
    • AT_PLUS.
    • REQUEST_PLUS.

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

 EXPLAIN SELECT * from customer WHERE zip = 94040 name name = “joe” and type =
“cx”;
 

Это медленно. Очень медленно. Ненужные выборки документов. Ненужная фильтрация. Впустую память и процессор. Первичное сканирование извлечет ВСЕ документы всех типов в корзине, независимо от того, вернет ли ваш запрос их пользователю. Хотя я сказал, что первичное сканирование похоже на сканирование таблицы, оно намного медленнее, чем сканирование таблицы, поскольку необходимо сканировать все документы всех типов.

Вы не должны использовать первичные индексы. Не используйте их. Особенно в производстве.

 Тогда почему у нас есть первичные индексы для начала?

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

    •  WHERE META().id between "cx:123" and "cx:458" 
  3. Когда вы знаете  конечный  шаблон META (). Id, как показано ниже

    •  WHERE META().id LIKE "cx:1%" 
    • НЕ используйте:  LIKE “%:123”. Это приведет к полной проверке
  4. Когда вы знаете полный META (). Id или список META (). Id, вы можете использовать USE KEYS для прямой выборки документа без обращения к первичному индексу.

    •  FROM customer USE KEYS ["cx:123"] 
    •  FROM customer USE KEYS ["cx:123", "cx:359", "cx:948"]
    • FROM customer USE KEYS(SELECT raw docid FROM mylist WHERE zip=94501) 

Основной индекс

Создайте первичный индекс на  ‘travel-sample’.

Первичный индекс — это просто индекс ключа документа во всей корзине. Уровень данных Couchbase обеспечивает ограничение уникальности ключа документа. Первичный индекс, как и любой другой индекс в Couchbase, поддерживается асинхронно. Вы устанавливаете актуальность данных, устанавливая  уровень согласованности  для вашего запроса.

Вот метаданные для этого индекса:

select * from system:indexes where name = ‘#primary’;
"indexes": {
  "datastore_id": "http://127.0.0.1:8091",
  "id": "f6e3c75d6f396e7d",
  "index_key": [],
  "is_primary": true,
  "keyspace_id": "travel-sample",
  "name": "#primary",
  "namespace_id": "default",
  "state": "online",
  "using": "gsi"
  }

Метаданные предоставляют дополнительную информацию об индексе: где находится индекс (datastore_id), его состояние (состояние) и метод индексации (использование).

Первичный индекс используется для полного сканирования сегментов (первичных сканирований), когда в запросе отсутствуют какие-либо фильтры (предикаты) или нельзя использовать другой индекс или путь доступа. В Couchbase вы храните несколько пространств клавиш (документы другого типа, клиенты, заказы, запасы и т. Д.) В одном контейнере.   

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

Дизайн ключа документа чем-то похож на дизайн первичного ключа с несколькими частями.

 Lastname:firstname:customerid 

 Example: smith:john:X1A1849 

In Couchbase, it’s a best practice to prefix the key with the type of the document. Since this is a customer document, let’s prefix with CX. Now, the key becomes:

 CX:smith:john:X1A1849 

So, in the same bucket, there will be other types of documents.

 ORDER type: OD:US:CA:294 

 ITEMS type:IT:KD92823 

These are simply best practices. There is no restriction on the format or structure of the document key in Couchbase, except they have to be unique within a bucket.

Now, if you have documents with various keys and have a primary index, you can use following queries to efficiently.

Example 1: Looking for a specific document key.


SELECT * FROM  sales WHERE META().id = “CX:smith:john:X1A1849”;

      {
        "#operator": "IndexScan2",
        "index": "#primary",
        "index_id": "4c92ab0bcca9690a",
        "keyspace": "sales",
        "namespace": "default",
        "spans": [
          {
            "exact": true,
            "range": [
              {
                "high": "\"CX:smith:john:X1A1849\"",
                "inclusion": 3,
                "low": "\"CX:smith:john:X1A1849\""
              }
            ]
          }
        ],

If you do know the full document key, you can use the following statement and avoid the index access altogether.

 SELECT * FROM sales USE KEYS ["CX:smith:john:X1A1849"] 

You can get more than one document in a statement.

 SELECT * FROM sales USE KEYS ["CX:smith:john:X1A1849", "CX:smithjr:john:X1A18492"]

Example 2:  Look for a pattern.  Get ALL the customer documents.

SELECT * FROM  sales WHERE META().id LIKE “CX:%”;
      {
        "#operator": "IndexScan2",
        "index": "#primary",
        "index_id": "4c92ab0bcca9690a",
        "keyspace": "sales",
        "namespace": "default",
        "spans": [
          {
            "exact": true,
            "range": [
              {
                "high": "\"CX;\"",
                "inclusion": 1,
                "low": "\"CX:\""
              }
            ]
          }
        ],

Example 3:  Get all the customers with smith as their last name.

The following query uses the primary index efficiently, only fetching the customers with a particular range. Note: This scan is case sensitive. To do a case insensitive scan, you’ve create a secondary index with UPPER() or LOWER() of the document key.

SELECT * FROM  sales WHERE META().id LIKE "CX:smith%";

      {
        "#operator": "IndexScan2",
        "index": "#primary",
        "index_id": "4c92ab0bcca9690a",
        "keyspace": "sales",
        "namespace": "default",
        "spans": [
          {
            "exact": true,
            "range": [
              {
                "high": "\"CX:smiti\"",
                "inclusion": 1,
                "low": "\"CX:smith\""
              }
            ]
          }
        ],

Example 4:  It’s common for some applications to use use an email address as part of the document key since they’re unique. In that case, you need to find out all of customers with gmail.com. If this is a typical requirement, then, store the REVERSE of of the email address as the key and simply do the scan of leading string pattern.

 Email:johnsmith@gmail.com      key: reverse("johnsmith@gmail.com") => 
moc.liamg@htimsnhoj 

 Email: janesnow@yahoo.com     key: reverse("janesnow@yahoo.com") => 
moc.oohay@wonsenaj
 

SELECT *
FROM  sales
WHERE meta().id LIKE (reverse("@yahoo.com") || "%");

        "#operator": "IndexScan2",
        "index": "#primary",
        "index_id": "4c92ab0bcca9690a",
        "keyspace": "sales",
        "namespace": "default",
        "spans": [
          {
            "range": [
              {
                "high": "\"moc.oohayA\"",
                "inclusion": 1,
                "low": "\"moc.oohay@\""
              }
            ]
          }
        ],

Named Primary Index

In Couchbase 5.0, you can create multiple replica of any index with a simple parameter to CREATE INDEX.  Following will create 3 copies of the index and there has to be minimum of 3 index nodes in the cluster.

 CRETE PRIMATY INDEX ON 'travel-simple' WITH{"num_replica":2}; CREATE PRIMARY
INDEX 'def_primary' ON 'travel-sample'; 
 

You can also name the primary index. The rest of the features of the primary index are the same, except the index is named. A good side effect of this is that you can have multiple primary indices in Couchbase versions before 5.0 using different names. Duplicate indices help with high availability as well as query load distribution throughout them.  This is true for both primary indices and secondary indices.

select meta().id as documentkey, `travel-sample` airline
from `travel-sample`
where type = 'airline' limit 1;
{
  "airline": {
    "callsign": "MILE-AIR",
    "country": "United States",
    "iata": "Q5",
    "icao": "MLA",
    "id": 10,
    "name": "40-Mile Air",
    "type": "airline"
  },
  "documentkey": "airline_10"
}

Finally, in Couchbase 6.5, we’ve introduced the Index advisor. It can analyze a single N1QL statement or workload. Read the details at:

  1. N1QL Index Advisor: Improve Query Performance and Productivity
  2. Index Advisor for N1QL Query Statement
  3. Index Advisor For Query Workload

This index advisor only advises suitable secondary indexes and never a primary index.  If you’ve read the article so far, you know why! 

Further Reading