azimutt icon indicating copy to clipboard operation
azimutt copied to clipboard

Improve Couchbase's support

Open ldoguin opened this issue 3 years ago • 2 comments

Thanks for supporting Couchbase Server! There are a bunch of things doable to improve it's general support.

  • [ ] Get the key and keyspace of the document in a meta field for each Azimutt Schema. The reason being that some JOINs are made with the key of the document. This is doable by adding Meta() as meta in the select clause.
  • [ ] Infer relationships through the existing queries and index. You can get them with SELECT * FROM system:indexes; and SELECT * FROM system:completed_requests;

ldoguin avatar Apr 27 '23 16:04 ldoguin

Added the Meta object on document query, we will have this object on every collection, I named it _meta to minimize conflicts and be explicit it's a special property.

I looked into the indexes on the sample bucket (travel-sample) but I don't know what to look, here are the results I get:

[
  {
    condition: '(`_type` = "User")',
    datastore_id: 'http://127.0.0.1:8091',
    id: 'c2dd55e30a1f1de6',
    index_key: [ '`name`' ],
    keyspace_id: 'travel-sample',
    name: 'def_name_type',
    namespace_id: 'default',
    state: 'online',
    using: 'gsi'
  },
  {
    condition: '(`type` = "route")',
    datastore_id: 'http://127.0.0.1:8091',
    id: '805ddfba2bf9e530',
    index_key: [
      '`sourceairport`',
      '`destinationairport`',
      '(distinct (array (`v`.`day`) for `v` in `schedule` end))'
    ],
    keyspace_id: 'travel-sample',
    name: 'def_route_src_dst_day',
    namespace_id: 'default',
    state: 'online',
    using: 'gsi'
  },
  {
    bucket_id: 'travel-sample',
    datastore_id: 'http://127.0.0.1:8091',
    id: 'df5d4e42cae537c4',
    index_key: [],
    is_primary: true,
    keyspace_id: 'airline',
    name: 'def_inventory_airline_primary',
    namespace_id: 'default',
    scope_id: 'inventory',
    state: 'online',
    using: 'gsi'
  },
  {
    bucket_id: 'travel-sample',
    datastore_id: 'http://127.0.0.1:8091',
    id: '8fd75114fc9d28c2',
    index_key: [ 'array (`s`.`utc`) for `s` in `schedule` end' ],
    keyspace_id: 'route',
    name: 'def_inventory_route_schedule_utc',
    namespace_id: 'default',
    scope_id: 'inventory',
    state: 'online',
    using: 'gsi'
  },
  {
    bucket_id: 'travel-sample',
    datastore_id: 'http://127.0.0.1:8091',
    id: '219e2dcd0b5e2306',
    index_key: [
      '`sourceairport`',
      '`destinationairport`',
      '(distinct (array (`v`.`day`) for `v` in `schedule` end))'
    ],
    keyspace_id: 'route',
    name: 'def_inventory_route_route_src_dst_day',
    namespace_id: 'default',
    scope_id: 'inventory',
    state: 'online',
    using: 'gsi'
  }
]

What I identified I could get from them:

  • show indexed columns (name on columns in index_key for those who don't have an expression)
  • primary keys (using is_primary), I'm a bit surprised to have only 2 globally, is it expected in Couchbase? I'm not sure what condition means, I feel like it could be important ^^ Also, any idea why sometimes the index_key is empty? Especially for the primary_key one? I have no idea on which field I should flag the primary key...

On the completed_requests I have no result, so I don't know how to expect from them ^^

But I didn't find how I could infer relations :/

I extracted the code in a separate lib so it will be easier experiment, here is the test with the commands: https://github.com/azimuttapp/azimutt/blob/main/libs/connector-couchbase/tests/couchbase.test.ts#L18

loicknuchel avatar Apr 30 '23 21:04 loicknuchel

The available results of completed requests really depends on what is configured to capture the request. Maybe a better route is to get the prepared statement with a query like Select meta().plan, statement from system:prepareds where contains(statement, "JOIN") OR contains(statement, "UNNEST") OR contains(statement, "NEST")

This could yield a results like

[
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.airport"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.route"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "IntersectScan",
                    "scans": [
                      {
                        "#operator": "IndexScan3",
                        "bucket": "travel-sample",
                        "index": "def_inventory_airport_faa",
                        "index_id": "425ef0580d0d0c67",
                        "index_projection": {
                          "primary_key": true
                        },
                        "keyspace": "airport",
                        "namespace": "default",
                        "scope": "inventory",
                        "spans": [
                          {
                            "exact": true,
                            "range": [
                              {
                                "inclusion": 0,
                                "index_key": "`faa`",
                                "low": "null"
                              }
                            ]
                          }
                        ],
                        "using": "gsi"
                      },
                      {
                        "#operator": "IndexScan3",
                        "bucket": "travel-sample",
                        "index": "def_inventory_airport_city",
                        "index_id": "549aea566dce6b5e",
                        "index_projection": {
                          "primary_key": true
                        },
                        "keyspace": "airport",
                        "namespace": "default",
                        "scope": "inventory",
                        "spans": [
                          {
                            "exact": true,
                            "range": [
                              {
                                "high": "\"San Francisco\"",
                                "inclusion": 3,
                                "index_key": "`city`",
                                "low": "\"San Francisco\""
                              }
                            ]
                          }
                        ],
                        "using": "gsi"
                      }
                    ]
                  },
                  {
                    "#operator": "Fetch",
                    "bucket": "travel-sample",
                    "keyspace": "airport",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Filter",
                          "condition": "(((`airport`.`city`) = \"San Francisco\") and ((`airport`.`faa`) is not null))"
                        }
                      ]
                    }
                  },
                  {
                    "#operator": "HashJoin",
                    "build_aliases": [
                      "subquery"
                    ],
                    "build_exprs": [
                      "(`subquery`.`sourceairport`)"
                    ],
                    "on_clause": "((`airport`.`faa`) = (`subquery`.`sourceairport`))",
                    "probe_exprs": [
                      "(`airport`.`faa`)"
                    ],
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Sequence",
                          "~children": [
                            {
                              "#operator": "PrimaryScan3",
                              "bucket": "travel-sample",
                              "index": "def_inventory_route_primary",
                              "index_projection": {
                                "primary_key": true
                              },
                              "keyspace": "route",
                              "namespace": "default",
                              "scope": "inventory",
                              "using": "gsi"
                            },
                            {
                              "#operator": "Fetch",
                              "bucket": "travel-sample",
                              "keyspace": "route",
                              "namespace": "default",
                              "scope": "inventory"
                            },
                            {
                              "#operator": "Parallel",
                              "~child": {
                                "#operator": "Sequence",
                                "~children": [
                                  {
                                    "#operator": "InitialProject",
                                    "result_terms": [
                                      {
                                        "expr": "(`route`.`destinationairport`)"
                                      },
                                      {
                                        "expr": "(`route`.`sourceairport`)"
                                      }
                                    ]
                                  }
                                ]
                              }
                            }
                          ]
                        },
                        {
                          "#operator": "Alias",
                          "as": "subquery",
                          "secondary_term": true
                        }
                      ]
                    }
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "InitialProject",
                          "distinct": true,
                          "result_terms": [
                            {
                              "expr": "(`subquery`.`destinationairport`)"
                            }
                          ]
                        },
                        {
                          "#operator": "Distinct"
                        }
                      ]
                    }
                  },
                  {
                    "#operator": "Distinct"
                  }
                ]
              },
              {
                "#operator": "Limit",
                "expr": "10"
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "prepare p4 as SELECT DISTINCT subquery.destinationairport \n    FROM `travel-sample`.inventory.airport \n    JOIN ( \n      SELECT destinationairport, sourceairport \n      FROM `travel-sample`.inventory.route \n    ) AS subquery \n    ON airport.faa = subquery.sourceairport \n    WHERE airport.city = \"San Francisco\"\n    LIMIT 10"
  },
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.route"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.airport"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.landmark"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "PrimaryScan3",
                    "as": "rte",
                    "bucket": "travel-sample",
                    "index": "def_inventory_route_primary",
                    "index_projection": {
                      "primary_key": true
                    },
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory",
                    "using": "gsi"
                  },
                  {
                    "#operator": "Fetch",
                    "as": "rte",
                    "bucket": "travel-sample",
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "NestedLoopJoin",
                          "alias": "apt",
                          "on_clause": "((`rte`.`destinationairport`) = (`apt`.`faa`))",
                          "~child": {
                            "#operator": "Sequence",
                            "~children": [
                              {
                                "#operator": "IndexScan3",
                                "as": "apt",
                                "bucket": "travel-sample",
                                "index": "def_inventory_airport_faa",
                                "index_id": "425ef0580d0d0c67",
                                "index_projection": {
                                  "primary_key": true
                                },
                                "keyspace": "airport",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory",
                                "spans": [
                                  {
                                    "exact": true,
                                    "range": [
                                      {
                                        "high": "(`rte`.`destinationairport`)",
                                        "inclusion": 3,
                                        "index_key": "`faa`",
                                        "low": "(`rte`.`destinationairport`)"
                                      }
                                    ]
                                  }
                                ],
                                "using": "gsi"
                              },
                              {
                                "#operator": "Fetch",
                                "as": "apt",
                                "bucket": "travel-sample",
                                "keyspace": "airport",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory"
                              }
                            ]
                          }
                        },
                        {
                          "#operator": "NestedLoopNest",
                          "alias": "lmk",
                          "on_clause": "((`apt`.`city`) = (`lmk`.`city`))",
                          "~child": {
                            "#operator": "Sequence",
                            "~children": [
                              {
                                "#operator": "IndexScan3",
                                "as": "lmk",
                                "bucket": "travel-sample",
                                "index": "def_inventory_landmark_city",
                                "index_id": "41d0d8cfe42ebcbe",
                                "index_projection": {
                                  "primary_key": true
                                },
                                "keyspace": "landmark",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory",
                                "spans": [
                                  {
                                    "exact": true,
                                    "range": [
                                      {
                                        "high": "(`apt`.`city`)",
                                        "inclusion": 3,
                                        "index_key": "`city`",
                                        "low": "(`apt`.`city`)"
                                      }
                                    ]
                                  }
                                ],
                                "using": "gsi"
                              },
                              {
                                "#operator": "Fetch",
                                "as": "lmk",
                                "bucket": "travel-sample",
                                "keyspace": "landmark",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory"
                              }
                            ]
                          }
                        },
                        {
                          "#operator": "InitialProject",
                          "result_terms": [
                            {
                              "expr": "self",
                              "star": true
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              },
              {
                "#operator": "Limit",
                "expr": "2"
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "prepare pnnest as SELECT * \n    FROM `travel-sample`.inventory.route AS rte \n    JOIN `travel-sample`.inventory.airport AS apt \n      ON rte.destinationairport = apt.faa \n    NEST `travel-sample`.inventory.landmark AS lmk \n      ON apt.city = lmk.city \n    LIMIT 2"
  },
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.route"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.airline"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "DistinctScan",
                    "scan": {
                      "#operator": "IndexScan3",
                      "as": "r",
                      "bucket": "travel-sample",
                      "index": "def_inventory_route_route_src_dst_day",
                      "index_id": "ac1bab4b598b61e8",
                      "index_projection": {
                        "primary_key": true
                      },
                      "keyspace": "route",
                      "namespace": "default",
                      "scope": "inventory",
                      "spans": [
                        {
                          "exact": true,
                          "range": [
                            {
                              "high": "\"SEA\"",
                              "inclusion": 3,
                              "index_key": "`sourceairport`",
                              "low": "\"SEA\""
                            },
                            {
                              "high": "\"MCO\"",
                              "inclusion": 3,
                              "index_key": "`destinationairport`",
                              "low": "\"MCO\""
                            }
                          ]
                        }
                      ],
                      "using": "gsi"
                    }
                  },
                  {
                    "#operator": "Fetch",
                    "as": "r",
                    "bucket": "travel-sample",
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Filter",
                          "condition": "(((`r`.`sourceairport`) = \"SEA\") and ((`r`.`destinationairport`) = \"MCO\") and is_array((`r`.`schedule`)))"
                        },
                        {
                          "#operator": "Unnest",
                          "as": "s",
                          "expr": "(`r`.`schedule`)",
                          "filter": "(((`s`.`day`) = 6) and (`s` is not missing))"
                        }
                      ]
                    }
                  },
                  {
                    "#operator": "Join",
                    "as": "a",
                    "bucket": "travel-sample",
                    "keyspace": "airline",
                    "namespace": "default",
                    "on_keys": "(`r`.`airlineid`)",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "InitialProject",
                          "result_terms": [
                            {
                              "expr": "(`a`.`name`)"
                            },
                            {
                              "expr": "(`s`.`flight`)"
                            },
                            {
                              "expr": "(`s`.`utc`)"
                            },
                            {
                              "expr": "(`r`.`sourceairport`)"
                            },
                            {
                              "expr": "(`r`.`destinationairport`)"
                            },
                            {
                              "expr": "(`r`.`equipment`)"
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              },
              {
                "#operator": "Order",
                "sort_terms": [
                  {
                    "expr": "random()"
                  }
                ]
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "PREPARE p1 as SELECT a.name, s.flight, s.utc, r.sourceairport, r.destinationairport, r.equipment\nFROM `travel-sample`.inventory.route r\nUNNEST r.schedule s\nJOIN `travel-sample`.inventory.airline a ON KEYS r.airlineid\nWHERE r.sourceairport='SEA' AND r.destinationairport='MCO' AND s.day=6\nORDER BY Random()"
  },
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.route"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.airline"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "PrimaryScan3",
                    "bucket": "travel-sample",
                    "index": "def_inventory_route_primary",
                    "index_projection": {
                      "primary_key": true
                    },
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory",
                    "using": "gsi"
                  },
                  {
                    "#operator": "Fetch",
                    "bucket": "travel-sample",
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Join",
                    "bucket": "travel-sample",
                    "keyspace": "airline",
                    "namespace": "default",
                    "on_keys": "(`route`.`airlineid`)",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Filter",
                          "condition": "((`airline`.`country`) = \"France\")"
                        },
                        {
                          "#operator": "InitialProject",
                          "result_terms": [
                            {
                              "expr": "self",
                              "star": true
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              },
              {
                "#operator": "Limit",
                "expr": "3"
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "prepare p3 as SELECT * \n    FROM `travel-sample`.inventory.route \n    JOIN `travel-sample`.inventory.airline \n    ON route.airlineid = META(airline).id \n    WHERE airline.country = \"France\" \n    LIMIT 3"
  },
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.hotel"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "PrimaryScan3",
                    "bucket": "travel-sample",
                    "index": "def_inventory_hotel_primary",
                    "index_projection": {
                      "primary_key": true
                    },
                    "keyspace": "hotel",
                    "namespace": "default",
                    "scope": "inventory",
                    "using": "gsi"
                  },
                  {
                    "#operator": "Fetch",
                    "bucket": "travel-sample",
                    "keyspace": "hotel",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Filter",
                          "condition": "is_array((`hotel`.`reviews`))"
                        },
                        {
                          "#operator": "Unnest",
                          "as": "r",
                          "expr": "(`hotel`.`reviews`)",
                          "filter": "((((`r`.`ratings`).`Rooms`) < 2) and (`r` is not missing))"
                        }
                      ]
                    }
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "InitialProject",
                          "raw": true,
                          "result_terms": [
                            {
                              "expr": "(`r`.`author`)"
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              },
              {
                "#operator": "Limit",
                "expr": "4"
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "prepare pnest as SELECT RAW r.author \n    FROM `travel-sample`.inventory.hotel \n    UNNEST reviews AS r \n    WHERE r.ratings.Rooms < 2 \n    LIMIT 4"
  },
  {
    "plan": {
      "#operator": "Authorize",
      "privileges": {
        "List": [
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.route"
          },
          {
            "Priv": 7,
            "Props": 0,
            "Target": "default:travel-sample.inventory.airport"
          }
        ]
      },
      "~child": {
        "#operator": "Sequence",
        "~children": [
          {
            "#operator": "Sequence",
            "~children": [
              {
                "#operator": "Sequence",
                "~children": [
                  {
                    "#operator": "IndexScan3",
                    "as": "rte",
                    "bucket": "travel-sample",
                    "index": "def_inventory_route_sourceairport",
                    "index_id": "44cf488c501bda75",
                    "index_projection": {
                      "primary_key": true
                    },
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory",
                    "spans": [
                      {
                        "exact": true,
                        "range": [
                          {
                            "high": "\"SFO\"",
                            "inclusion": 3,
                            "index_key": "`sourceairport`",
                            "low": "\"SFO\""
                          }
                        ]
                      }
                    ],
                    "using": "gsi"
                  },
                  {
                    "#operator": "Fetch",
                    "as": "rte",
                    "bucket": "travel-sample",
                    "keyspace": "route",
                    "namespace": "default",
                    "scope": "inventory"
                  },
                  {
                    "#operator": "Parallel",
                    "~child": {
                      "#operator": "Sequence",
                      "~children": [
                        {
                          "#operator": "Filter",
                          "condition": "((`rte`.`sourceairport`) = \"SFO\")"
                        },
                        {
                          "#operator": "NestedLoopJoin",
                          "alias": "apt",
                          "on_clause": "((`rte`.`destinationairport`) = (`apt`.`faa`))",
                          "~child": {
                            "#operator": "Sequence",
                            "~children": [
                              {
                                "#operator": "IndexScan3",
                                "as": "apt",
                                "bucket": "travel-sample",
                                "index": "def_inventory_airport_faa",
                                "index_id": "425ef0580d0d0c67",
                                "index_projection": {
                                  "primary_key": true
                                },
                                "keyspace": "airport",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory",
                                "spans": [
                                  {
                                    "exact": true,
                                    "range": [
                                      {
                                        "high": "(`rte`.`destinationairport`)",
                                        "inclusion": 3,
                                        "index_key": "`faa`",
                                        "low": "(`rte`.`destinationairport`)"
                                      }
                                    ]
                                  }
                                ],
                                "using": "gsi"
                              },
                              {
                                "#operator": "Fetch",
                                "as": "apt",
                                "bucket": "travel-sample",
                                "keyspace": "airport",
                                "namespace": "default",
                                "nested_loop": true,
                                "scope": "inventory"
                              }
                            ]
                          }
                        },
                        {
                          "#operator": "InitialProject",
                          "result_terms": [
                            {
                              "expr": "self",
                              "star": true
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              },
              {
                "#operator": "Limit",
                "expr": "5"
              }
            ]
          },
          {
            "#operator": "Stream"
          }
        ]
      }
    },
    "statement": "PREPARE p2 as SELECT * \n    FROM `travel-sample`.inventory.route AS rte \n        JOIN `travel-sample`.inventory.airport AS apt ON rte.destinationairport = apt.faa \n    WHERE rte.sourceairport='SFO' \n    LIMIT 5"
  }
]

ldoguin avatar May 04 '23 13:05 ldoguin