> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Explore ClickHouse con un conjunto de datos de miles de millones de viajes en taxi y vehículos de alquiler con conductor (Uber, Lyft, etc.) con origen en la ciudad de Nueva York desde 2009

# Análisis geoespacial con el conjunto de datos de taxis de Nueva York

export const RunnableCode = ({children, run = false, showStats = true}) => {
  const [results, setResults] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [showResults, setShowResults] = useState(false);
  const [stats, setStats] = useState(null);
  const [isDark, setIsDark] = useState(false);
  const [hoveredRow, setHoveredRow] = useState(-1);
  const codeRef = useRef(null);
  useEffect(() => {
    if (typeof window !== "undefined") {
      const check = () => setIsDark(document.documentElement.classList.contains("dark"));
      check();
      const observer = new MutationObserver(check);
      observer.observe(document.documentElement, {
        attributes: true,
        attributeFilter: ["class"]
      });
      return () => observer.disconnect();
    }
  }, []);
  useEffect(() => {
    if (codeRef.current) {
      const block = codeRef.current.querySelector(".code-block");
      if (block) {
        block.style.marginBottom = "0";
        block.style.marginTop = "0";
        block.style.borderBottomLeftRadius = "0";
        block.style.borderBottomRightRadius = "0";
      }
    }
  });
  const getSqlText = () => {
    if (!codeRef.current) return "";
    const code = codeRef.current.querySelector("code");
    return (code || codeRef.current).textContent.trim();
  };
  const executeQuery = async () => {
    const sql = getSqlText();
    if (!sql) return;
    setLoading(true);
    setError(null);
    setResults(null);
    setShowResults(true);
    try {
      const cleanQuery = sql.replace(/;$/, "").trim();
      const params = new URLSearchParams({
        query: cleanQuery,
        default_format: "JSONCompact",
        result_overflow_mode: "break",
        read_overflow_mode: "break",
        allow_experimental_analyzer: "1"
      });
      const res = await fetch(`https://sql-clickhouse.clickhouse.com/?${params.toString()}`, {
        method: "POST",
        headers: {
          Authorization: `Basic ${btoa(`demo:`)}`
        }
      });
      const text = await res.text();
      if (!res.ok) {
        setError(text || `HTTP ${res.status}`);
        setLoading(false);
        return;
      }
      const json = JSON.parse(text);
      setResults(json);
      setStats(json.statistics || null);
    } catch (err) {
      setError(err.message || "Error al ejecutar la consulta");
    }
    setLoading(false);
  };
  useEffect(() => {
    if (run) executeQuery();
  }, []);
  const formatRows = n => {
    if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B`;
    if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
    if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
    return String(n);
  };
  const formatBytes = b => {
    if (b >= 1e9) return `${(b / 1e9).toFixed(2)} GB`;
    if (b >= 1e6) return `${(b / 1e6).toFixed(2)} MB`;
    if (b >= 1e3) return `${(b / 1e3).toFixed(2)} KB`;
    return `${b} B`;
  };
  const isNumericType = type => {
    return (/^(UInt|Int|Float|Decimal)/).test(type);
  };
  const isHyperlink = value => {
    return typeof value === "string" && (/^https?:\/\//).test(value);
  };
  const computeColumnExtremes = (meta, data) => {
    const extremes = {};
    for (let i = 0; i < meta.length; i++) {
      if (isNumericType(meta[i].type)) {
        let min = Infinity, max = -Infinity;
        for (const row of data) {
          const v = Number(row[i]);
          if (!isNaN(v)) {
            if (v < min) min = v;
            if (v > max) max = v;
          }
        }
        if (max > -Infinity) {
          extremes[i] = {
            min,
            max
          };
        }
      }
    }
    return extremes;
  };
  const computeColumnWidths = (meta, data) => {
    const lengths = meta.map((col, i) => {
      const headerLen = col.name.length + col.type.length + 1;
      let maxData = 0;
      for (const row of data) {
        const v = row[i];
        const len = v === null ? 4 : String(v).length;
        if (len > maxData) maxData = len;
      }
      return Math.max(headerLen, maxData);
    });
    const total = lengths.reduce((s, l) => s + l, 0);
    return lengths.map(l => `${(l / total * 100).toFixed(1)}%`);
  };
  const copyResultsAsTSV = () => {
    if (!results || !results.meta || !results.data) return;
    const header = results.meta.map(col => col.name).join("\t");
    const rows = results.data.map(row => row.map(cell => cell === null ? "NULL" : String(cell)).join("\t"));
    const tsv = [header, ...rows].join("\n");
    navigator.clipboard.writeText(tsv);
  };
  const borderColor = isDark ? "rgba(255,255,255,0.15)" : "#e5e7eb";
  const bgColor = isDark ? "rgba(255,255,255,0.05)" : "#f9fafb";
  const headerBg = isDark ? "#2a2a2a" : "#f3f4f6";
  const textColor = isDark ? "#e5e7eb" : "#1f2937";
  const mutedColor = isDark ? "#d1d5db" : "#6b7280";
  const accentColor = isDark ? "#FAFF69" : "#323232";
  const accentTextColor = isDark ? "#000" : "#fff";
  const barColor = isDark ? "#35372f" : "#d2d2d2";
  const cellBg = isDark ? "#1f201b" : "#ffffff";
  const cellBgHover = isDark ? "lch(15.8 0 0)" : "#f0f0f0";
  const extremes = results && results.meta && results.data ? computeColumnExtremes(results.meta, results.data) : {};
  const colWidths = results && results.meta && results.data ? computeColumnWidths(results.meta, results.data) : [];
  const getCellBarStyle = (cell, ci, ri) => {
    if (cell === null) return null;
    const colMeta = results.meta[ci];
    if (!isNumericType(colMeta.type) || !extremes[ci] || results.data.length <= 1 || extremes[ci].max <= 0) return null;
    const ratio = 100 * Number(cell) / extremes[ci].max;
    const bg = ri === hoveredRow ? cellBgHover : cellBg;
    return {
      background: `linear-gradient(to right, ${barColor} 0%, ${barColor} ${ratio}%, ${bg} ${ratio}%, ${bg} 100%)`
    };
  };
  const renderCell = (cell, ci) => {
    if (cell === null) {
      return <span style={{
        color: mutedColor,
        fontStyle: "italic"
      }}>NULL</span>;
    }
    const value = String(cell);
    if (isHyperlink(value)) {
      return <a href={value} target="_blank" rel="noopener noreferrer" style={{
        color: accentColor,
        textDecoration: "underline",
        cursor: "pointer"
      }}>
          {value}
        </a>;
    }
    return value;
  };
  return <div className="not-prose" style={{
    margin: "1rem 0",
    width: "100%",
    boxSizing: "border-box",
    contain: "inline-size"
  }}>
      {}
      <div>
        <div ref={codeRef}>{children}</div>

        {}
        <div style={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    padding: "6px 12px",
    backgroundColor: headerBg,
    borderWidth: "0 1px 1px 1px",
    borderStyle: "solid",
    borderColor: isDark ? "rgba(255,255,255,0.1)" : "rgba(11,11,11,0.1)",
    borderRadius: "0 0 4px 4px"
  }}>
          <div style={{
    display: "flex",
    alignItems: "center",
    gap: "12px"
  }}>
            {results && <button onClick={() => setShowResults(!showResults)} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    color: mutedColor,
    fontSize: "12px",
    padding: "2px 4px"
  }}>
                {showResults ? "▼ Ocultar resultados" : "▶ Mostrar resultados"}
              </button>}
            {showStats && stats && <span style={{
    fontSize: "11px",
    color: mutedColor,
    fontStyle: "italic"
  }}>
                Leídas {formatRows(stats.rows_read)} filas, {formatBytes(stats.bytes_read)} en {stats.elapsed.toFixed(3)}s
              </span>}
          </div>
          <button onClick={() => executeQuery()} disabled={loading} style={{
    display: "flex",
    alignItems: "center",
    gap: "6px",
    padding: "4px 14px",
    borderRadius: "4px",
    border: "none",
    cursor: loading ? "wait" : "pointer",
    backgroundColor: accentColor,
    color: accentTextColor,
    fontSize: "12px",
    fontWeight: 600
  }}>
            {loading ? <span>Ejecutando...</span> : <>
                <span style={{
    fontSize: "10px"
  }}>▶</span>
                <span>Ejecutar</span>
              </>}
          </button>
        </div>
      </div>

      {}
      {showResults && <div className="not-prose" style={{
    marginTop: "8px",
    maxHeight: "350px",
    overflow: "auto",
    border: `1px solid ${borderColor}`,
    borderRadius: "4px"
  }}>
          <div>
            {loading && <div style={{
    padding: "24px",
    textAlign: "center",
    color: mutedColor
  }}>Ejecutando consulta...</div>}

            {error && <div style={{
    padding: "12px 16px",
    color: "#ef4444",
    backgroundColor: isDark ? "rgba(239,68,68,0.1)" : "#fef2f2",
    fontSize: "13px",
    fontFamily: "monospace",
    whiteSpace: "pre-wrap"
  }}>
                {error}
              </div>}

            {results && results.meta && results.data && <div style={{
    display: "grid",
    gridTemplateColumns: colWidths.join(" "),
    width: "100%",
    fontSize: "13px",
    fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace'
  }}>
                {results.meta.map((col, i) => <div key={`h-${i}`} style={{
    position: "sticky",
    top: 0,
    zIndex: 1,
    padding: "6px 12px",
    textAlign: isNumericType(col.type) && results.meta.length > 1 ? "right" : "left",
    backgroundColor: headerBg,
    borderBottom: `1px solid ${borderColor}`,
    color: textColor,
    fontWeight: 600,
    fontSize: "12px",
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis"
  }}>
                    {col.name}
                    <span style={{
    color: mutedColor,
    fontWeight: 400,
    marginLeft: "4px",
    fontSize: "10px"
  }}>{col.type}</span>
                  </div>)}
                {results.data.map((row, ri) => row.map((cell, ci) => <div key={`${ri}-${ci}`} onMouseEnter={() => setHoveredRow(ri)} onMouseLeave={() => setHoveredRow(-1)} style={{
    padding: "4px 12px",
    color: textColor,
    whiteSpace: "nowrap",
    overflow: "hidden",
    textOverflow: "ellipsis",
    textAlign: isNumericType(results.meta[ci].type) && results.meta.length > 1 ? "right" : "left",
    borderBottom: `1px solid ${borderColor}`,
    backgroundColor: ri === hoveredRow ? cellBgHover : ri % 2 === 0 ? "transparent" : bgColor,
    ...getCellBarStyle(cell, ci, ri)
  }}>
                      {renderCell(cell, ci)}
                    </div>))}
              </div>}

            {results && results.data && <div style={{
    display: "flex",
    justifyContent: "space-between",
    alignItems: "center",
    padding: "4px 12px",
    fontSize: "11px",
    color: mutedColor,
    borderTop: `1px solid ${borderColor}`,
    backgroundColor: headerBg
  }}>
                <span>
                  {results.rows} fila{results.rows !== 1 ? "s" : ""}
                </span>
                <button onClick={copyResultsAsTSV} style={{
    background: "none",
    border: "none",
    cursor: "pointer",
    color: mutedColor,
    fontSize: "11px",
    padding: "2px 6px",
    borderRadius: "3px"
  }} onMouseEnter={e => e.target.style.color = textColor} onMouseLeave={e => e.target.style.color = mutedColor}>
                  ⧉ Copiar TSV
                </button>
              </div>}
          </div>
        </div>}
    </div>;
};

<View title="Cloud">
  En este tutorial, descubrirá cómo usar ClickHouse para ejecutar consultas analíticas sobre grandes volúmenes de datos.
  También verá cómo utilizar un diccionario para enriquecer los datos y escribir consultas con JOIN.

  ## Requisitos previos

  Para este tutorial, necesitará:

  * Una [cuenta de ClickHouse Cloud](https://clickhouse.cloud/signUp?loc=docs-sample-datasets-nyc-taxi) (300 USD en créditos gratuitos al registrarte)
  * [Un servicio de ClickHouse Cloud](/es/get-started/setup/cloud#1-create-a-clickhouse-service)

  <Steps titleSize="h2">
    <Step title="Cree la tabla" id="create-a-new-table">
      El conjunto de datos que se utiliza en este tutorial es el de los taxis de la ciudad de Nueva York, que contiene información sobre millones de viajes en taxi, con columnas como el importe de la propina, los peajes, el tipo de pago, entre otras.

      1. Seleccione **SQL console** en el menú de la izquierda
      2. Haga clic en la pestaña **+** situada junto al icono de inicio para crear una nueva consulta
      3. En el editor SQL, escriba la siguiente consulta y, a continuación, haga clic en **Run**:

      ```sql Expandable theme={null}
      CREATE TABLE trips
      (
          `trip_id` UInt32,
          `vendor_id` Enum8('1' = 1, '2' = 2, '3' = 3, '4' = 4, 'CMT' = 5, 'VTS' = 6, 'DDS' = 7, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14, '' = 15),
          `pickup_date` Date,
          `pickup_datetime` DateTime,
          `dropoff_date` Date,
          `dropoff_datetime` DateTime,
          `store_and_fwd_flag` UInt8,
          `rate_code_id` UInt8,
          `pickup_longitude` Float64,
          `pickup_latitude` Float64,
          `dropoff_longitude` Float64,
          `dropoff_latitude` Float64,
          `passenger_count` UInt8,
          `trip_distance` Float64,
          `fare_amount` Float32,
          `extra` Float32,
          `mta_tax` Float32,
          `tip_amount` Float32,
          `tolls_amount` Float32,
          `ehail_fee` Float32,
          `improvement_surcharge` Float32,
          `total_amount` Float32,
          `payment_type` Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
          `trip_type` UInt8,
          `pickup` FixedString(25),
          `dropoff` FixedString(25),
          `cab_type` Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
          `pickup_nyct2010_gid` Int8,
          `pickup_ctlabel` Float32,
          `pickup_borocode` Int8,
          `pickup_ct2010` String,
          `pickup_boroct2010` String,
          `pickup_cdeligibil` String,
          `pickup_ntacode` FixedString(4),
          `pickup_ntaname` String,
          `pickup_puma` UInt16,
          `dropoff_nyct2010_gid` UInt8,
          `dropoff_ctlabel` Float32,
          `dropoff_borocode` UInt8,
          `dropoff_ct2010` String,
          `dropoff_boroct2010` String,
          `dropoff_cdeligibil` String,
          `dropoff_ntacode` FixedString(4),
          `dropoff_ntaname` String,
          `dropoff_puma` UInt16
      )
      ENGINE = MergeTree
      PARTITION BY toYYYYMM(pickup_date)
      ORDER BY pickup_datetime;
      ```
    </Step>

    <Step title="Inserte los datos" id="add-the-dataset">
      Ahora que ha creado una tabla, añada los datos de taxis de la ciudad de Nueva York a partir de archivos CSV almacenados en S3.

      El siguiente comando inserta aproximadamente 2.000.000 de filas en su tabla trips a partir de dos archivos distintos en S3: `trips_1.tsv.gz` y `trips_2.tsv.gz`:

      ```sql Expandable theme={null}
      INSERT INTO trips
      SELECT * FROM s3(
          'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/trips_{1..2}.gz',
          'TabSeparatedWithNames', "
          `trip_id` UInt32,
          `vendor_id` Enum8('1' = 1, '2' = 2, '3' = 3, '4' = 4, 'CMT' = 5, 'VTS' = 6, 'DDS' = 7, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14, '' = 15),
          `pickup_date` Date,
          `pickup_datetime` DateTime,
          `dropoff_date` Date,
          `dropoff_datetime` DateTime,
          `store_and_fwd_flag` UInt8,
          `rate_code_id` UInt8,
          `pickup_longitude` Float64,
          `pickup_latitude` Float64,
          `dropoff_longitude` Float64,
          `dropoff_latitude` Float64,
          `passenger_count` UInt8,
          `trip_distance` Float64,
          `fare_amount` Float32,
          `extra` Float32,
          `mta_tax` Float32,
          `tip_amount` Float32,
          `tolls_amount` Float32,
          `ehail_fee` Float32,
          `improvement_surcharge` Float32,
          `total_amount` Float32,
          `payment_type` Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),
          `trip_type` UInt8,
          `pickup` FixedString(25),
          `dropoff` FixedString(25),
          `cab_type` Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),
          `pickup_nyct2010_gid` Int8,
          `pickup_ctlabel` Float32,
          `pickup_borocode` Int8,
          `pickup_ct2010` String,
          `pickup_boroct2010` String,
          `pickup_cdeligibil` String,
          `pickup_ntacode` FixedString(4),
          `pickup_ntaname` String,
          `pickup_puma` UInt16,
          `dropoff_nyct2010_gid` UInt8,
          `dropoff_ctlabel` Float32,
          `dropoff_borocode` UInt8,
          `dropoff_ct2010` String,
          `dropoff_boroct2010` String,
          `dropoff_cdeligibil` String,
          `dropoff_ntacode` FixedString(4),
          `dropoff_ntaname` String,
          `dropoff_puma` UInt16
      ") SETTINGS input_format_try_infer_datetimes = 0
      ```

      Espere a que finalice la inserción de los datos. Se descargarán alrededor de 150 MB de datos.
      Una vez finalizada la inserción, compruebe el número de filas de la tabla `trips`:

      ```sql theme={null}
      SELECT count() FROM trips
      ```

      Deberías obtener como resultado 1,999,657 filas
    </Step>

    <Step title="Analice los datos" id="analyze-the-data">
      Con los datos ya cargados, puede ejecutar algunas consultas para analizarlos.

      * Calcule el importe medio de las propinas:
        ```sql theme={null}
        SELECT round(avg(tip_amount), 2) FROM trips
        ```

      * Calcule el coste medio en función del número de pasajeros:
        ```sql theme={null}
        SELECT
            passenger_count,
            ceil(avg(total_amount),2) AS average_total_amount
        FROM trips
        GROUP BY passenger_count
        ```

      * Calcule el número diario de recogidas por barrio:
        ```sql theme={null}
        SELECT
          pickup_date,
          pickup_ntaname,
          SUM(1) AS number_of_trips
        FROM trips
        GROUP BY pickup_date, pickup_ntaname
        ORDER BY pickup_date ASC
        ```

      * Calcule la duración de cada viaje en minutos y agrupe los resultados según esa duración:
        ```sql theme={null}
        SELECT
          avg(tip_amount) AS avg_tip,
          avg(fare_amount) AS avg_fare,
          avg(passenger_count) AS avg_passenger,
          count() AS count,
          truncate(date_diff('second', pickup_datetime, dropoff_datetime)/60) as trip_minutes
        FROM trips
        WHERE trip_minutes > 0
        GROUP BY trip_minutes
        ORDER BY trip_minutes DESC
        ```

      * Muestre el número de recogidas en cada barrio, desglosado por hora del día:
        ```sql theme={null}
        SELECT
            pickup_ntaname,
            toHour(pickup_datetime) as pickup_hour,
            SUM(1) AS pickups
        FROM trips
        WHERE pickup_ntaname != ''
        GROUP BY pickup_ntaname, pickup_hour
        ORDER BY pickup_ntaname, pickup_hour
        ```
    </Step>

    <Step title="Cree un diccionario" id="create-a-dictionary">
      A continuación, creará un diccionario (una correspondencia de pares clave-valor almacenada en memoria) llamado `taxi_zone_dictionary` que asocia los ID de ubicación con los nombres de los distritos de NYC, a partir de un archivo CSV que contiene todos los barrios de la ciudad de Nueva York.
      Estos ID corresponden a las columnas `pickup_nyct2010_gid` y `dropoff_nyct2010_gid` de la tabla trips.

      A continuación se muestra, en formato de tabla, un extracto del archivo CSV que va a utilizar. La columna `LocationID` del archivo se corresponde con las columnas `pickup_nyct2010_gid` y `dropoff_nyct2010_gid` de su tabla `trips`:

      | LocationID | Borough | Zone | service\_zone |
      | - | - | - | - |
      | 1 | EWR | Newark Airport | EWR |
      | 2 | Queens | Jamaica Bay | Boro Zone |
      | 3 | Bronx | Allerton/Pelham Gardens | Boro Zone |
      | 4 | Manhattan | Alphabet City | Yellow Zone |
      | 5 | Staten Island | Arden Heights | Boro Zone |

      Ejecute el siguiente comando SQL, que crea un diccionario llamado `taxi_zone_dictionary` y lo puebla con los datos del archivo CSV almacenado en S3. La URL del archivo es `https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/taxi_zone_lookup.csv`.

      ```sql theme={null}
      CREATE DICTIONARY taxi_zone_dictionary
      (
        `LocationID` UInt16 DEFAULT 0,
        `Borough` String,
        `Zone` String,
        `service_zone` String
      )
      PRIMARY KEY LocationID
      SOURCE(HTTP(URL 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/taxi_zone_lookup.csv' FORMAT 'CSVWithNames'))
      LIFETIME(MIN 0 MAX 0)
      LAYOUT(HASHED_ARRAY())
      ```

      <Note>
        Si se establece `LIFETIME` en 0, se desactivan las actualizaciones automáticas para evitar tráfico innecesario hacia nuestro bucket de S3. En otros casos, puede que le convenga configurarlo de otra forma. Para obtener más información, consulte [Actualización de los datos del diccionario mediante LIFETIME](/es/reference/statements/create/dictionary/lifetime).
      </Note>

      Compruebe que ha funcionado. La siguiente consulta debería devolver 265 filas, es decir, una por cada barrio:

      ```sql theme={null}
      SELECT * FROM taxi_zone_dictionary
      ```
    </Step>

    <Step title="Ejecutar consultas con el diccionario">
      Puede usar la función `dictGet` ([o sus variantes](/es/reference/functions/regular-functions/ext-dict-functions)) para obtener un valor de un diccionario.
      Basta con indicar el nombre del diccionario, el valor que desea y la clave (que en nuestro ejemplo es la columna `LocationID` de `taxi_zone_dictionary`) para obtener el valor correspondiente.
      Por ejemplo, la siguiente consulta devuelve el `Borough` cuyo `LocationID` es 132 (que corresponde al aeropuerto JFK):

      ```sql theme={null}
      SELECT dictGet('taxi_zone_dictionary', 'Borough', 132)
      ```

      JFK está en Queens. Observe que el tiempo necesario para obtener el valor es prácticamente 0:

      ```response theme={null}
      ┌─dictGet('taxi_zone_dictionary', 'Borough', 132)─┐
      │ Queens                                          │
      └─────────────────────────────────────────────────┘

      1 rows in set. Elapsed: 0.004 sec.
      ```

      Use la función `dictHas` para comprobar si una clave existe en el diccionario. Por ejemplo, la siguiente consulta devuelve `1` (que en ClickHouse equivale a "true"):

      ```sql theme={null}
      SELECT dictHas('taxi_zone_dictionary', 132)
      ```

      La siguiente consulta devuelve 0 porque 4567 no es un valor de `LocationID` del diccionario:

      ```sql theme={null}
      SELECT dictHas('taxi_zone_dictionary', 4567)
      ```

      Utilice la función `dictGet` para obtener el nombre de un distrito en una consulta. Por ejemplo:

      ```sql theme={null}
      SELECT
        count(1) AS total,
        dictGetOrDefault('taxi_zone_dictionary','Borough', toUInt64(pickup_nyct2010_gid), 'Unknown') AS borough_name
      FROM trips
      WHERE dropoff_nyct2010_gid = 132 OR dropoff_nyct2010_gid = 138
      GROUP BY borough_name
      ORDER BY total DESC
      ```

      Esta consulta suma el número de viajes en taxi por distrito que terminan en el aeropuerto de LaGuardia o en el de JFK. El resultado es el siguiente; observe que hay bastantes viajes cuyo barrio de recogida se desconoce:

      ```response theme={null}
      ┌─total─┬─borough_name──┐
      │ 23683 │ Unknown       │
      │  7053 │ Manhattan     │
      │  6828 │ Brooklyn      │
      │  4458 │ Queens        │
      │  2670 │ Bronx         │
      │   554 │ Staten Island │
      │    53 │ EWR           │
      └───────┴───────────────┘

      7 rows in set. Elapsed: 0.019 sec. Processed 2.00 million rows, 4.00 MB (105.70 million rows/s., 211.40 MB/s.)
      ```
    </Step>

    <Step title="Realizar un JOIN" id="perform-a-join">
      Por último, escriba algunas consultas que hagan un join de `taxi_zone_dictionary` con su tabla `trips`.

      Comience con un `JOIN` sencillo que funcione de forma similar a la consulta anterior sobre aeropuertos:

      ```sql theme={null}
      SELECT
          count(1) AS total,
          Borough
      FROM trips
      JOIN taxi_zone_dictionary ON toUInt64(trips.pickup_nyct2010_gid) = taxi_zone_dictionary.LocationID
      WHERE dropoff_nyct2010_gid = 132 OR dropoff_nyct2010_gid = 138
      GROUP BY Borough
      ORDER BY total DESC
      ```

      La respuesta es idéntica a la de la consulta con `dictGet`:

      ```response theme={null}
      ┌─total─┬─Borough───────┐
      │  7053 │ Manhattan     │
      │  6828 │ Brooklyn      │
      │  4458 │ Queens        │
      │  2670 │ Bronx         │
      │   554 │ Staten Island │
      │    53 │ EWR           │
      └───────┴───────────────┘

      6 rows in set. Elapsed: 0.034 sec. Processed 2.00 million rows, 4.00 MB (59.14 million rows/s., 118.29 MB/s.)
      ```

      <Note>
        Observe que el resultado de la consulta `JOIN` anterior es el mismo que el de la consulta previa que usaba `dictGetOrDefault` (salvo que no se incluyen los valores `Unknown`).
        Internamente, ClickHouse está llamando a la función `dictGet` sobre el diccionario `taxi_zone_dictionary`, pero la sintaxis `JOIN` resulta más familiar para los desarrolladores de SQL.
      </Note>

      Esta consulta devuelve las filas de los 1000 viajes con el importe de propina más alto y, a continuación, realiza un inner join de cada fila con el diccionario:

      ```sql theme={null}
      SELECT *
      FROM trips
      JOIN taxi_zone_dictionary
      ON trips.dropoff_nyct2010_gid = taxi_zone_dictionary.LocationID
      WHERE tip_amount > 0
      ORDER BY tip_amount DESC
      LIMIT 1000
      ```

      <Tip>
        Es preferible enumerar solo las columnas que necesita su consulta en lugar de usar SELECT \*. Como ClickHouse almacena los datos por columnas, seleccionar menos columnas reduce directamente el volumen de datos que se leen, descomprimen y procesan.
      </Tip>
    </Step>
  </Steps>

  ## Próximos pasos

  Obtenga más información sobre ClickHouse en la siguiente documentación:

  * [Introducción a los índices primarios en ClickHouse](/es/guides/clickhouse/data-modelling/sparse-primary-indexes): Descubra cómo ClickHouse utiliza índices primarios dispersos para localizar de forma eficiente los datos relevantes durante las consultas.
  * [Integrar una fuente de datos externa](/es/integrations/home): Consulte las opciones de integración de fuentes de datos, como archivos, Kafka, PostgreSQL, canalizaciones de datos y muchas más.
  * [Visualizar datos en ClickHouse](/es/integrations/connectors/data-visualization/index): Conecte su herramienta de UI/BI favorita a ClickHouse.
  * [Referencia de SQL](/es/reference/home): Explore las funciones SQL disponibles en ClickHouse para transformar, procesar y analizar datos.
</View>

<View title="Código abierto">
  La muestra de datos de taxis de Nueva York incluye más de 3000 millones de viajes en taxi y en vehículos de alquiler con conductor (Uber, Lyft, etc.) con origen en la ciudad de Nueva York desde 2009. Esta guía de introducción utiliza una muestra de 3 millones de filas.

  El conjunto de datos completo se puede obtener de dos maneras:

  * insertar los datos directamente en ClickHouse Cloud desde S3 o GCS
  * descargar particiones preparadas
  * Como alternativa, puede consultar el conjunto de datos completo en nuestro entorno de demostración en [sql.clickhouse.com](https://sql.clickhouse.com/?query=U0VMRUNUIGNvdW50KCkgRlJPTSBueWNfdGF4aS50cmlwcw\&chart=eyJ0eXBlIjoibGluZSIsImNvbmZpZyI6eyJ0aXRsZSI6IlRlbXBlcmF0dXJlIGJ5IGNvdW50cnkgYW5kIHllYXIiLCJ4YXhpcyI6InllYXIiLCJ5YXhpcyI6ImNvdW50KCkiLCJzZXJpZXMiOiJDQVNUKHBhc3Nlbmdlcl9jb3VudCwgJ1N0cmluZycpIn19).

  <Note>
    Las consultas de ejemplo que se muestran a continuación se ejecutaron en una instancia **Production** de ClickHouse Cloud. Para obtener más información, consulte
    ["Especificaciones del Playground"](/es/get-started/sample-datasets/playground#specifications).
  </Note>

  ## Crear la tabla trips

  Comience creando una tabla para los viajes en taxi:

  ```sql theme={null}

  CREATE DATABASE nyc_taxi;

  CREATE TABLE nyc_taxi.trips_small (
      trip_id             UInt32,
      pickup_datetime     DateTime,
      dropoff_datetime    DateTime,
      pickup_longitude    Nullable(Float64),
      pickup_latitude     Nullable(Float64),
      dropoff_longitude   Nullable(Float64),
      dropoff_latitude    Nullable(Float64),
      passenger_count     UInt8,
      trip_distance       Float32,
      fare_amount         Float32,
      extra               Float32,
      tip_amount          Float32,
      tolls_amount        Float32,
      total_amount        Float32,
      payment_type        Enum('CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4, 'UNK' = 5),
      pickup_ntaname      LowCardinality(String),
      dropoff_ntaname     LowCardinality(String)
  )
  ENGINE = MergeTree
  PRIMARY KEY (pickup_datetime, dropoff_datetime);
  ```

  ## Cargar los datos directamente desde el almacenamiento de objetos

  Los usuarios pueden obtener un pequeño subconjunto de los datos (3 millones de filas) para familiarizarse con ellos. Los datos están en archivos TSV alojados en almacenamiento de objetos, desde donde pueden transmitirse fácilmente a
  ClickHouse Cloud mediante la función de tabla `s3`.

  Los mismos datos están almacenados tanto en S3 como en GCS; puede elegir cualquiera de las dos pestañas.

  <Tabs>
    <Tab title="S3">
      El siguiente comando transfiere en streaming tres archivos desde un bucket de S3 a la tabla `trips_small` (la sintaxis `{0..2}` es un comodín para los valores 0, 1 y 2):

      ```sql theme={null}
      INSERT INTO nyc_taxi.trips_small
      SELECT
          trip_id,
          pickup_datetime,
          dropoff_datetime,
          pickup_longitude,
          pickup_latitude,
          dropoff_longitude,
          dropoff_latitude,
          passenger_count,
          trip_distance,
          fare_amount,
          extra,
          tip_amount,
          tolls_amount,
          total_amount,
          payment_type,
          pickup_ntaname,
          dropoff_ntaname
      FROM s3(
          'https://datasets-documentation.s3.eu-west-3.amazonaws.com/nyc-taxi/trips_{0..2}.gz',
          'TabSeparatedWithNames'
      );
      ```
    </Tab>

    <Tab title="GCS">
      El siguiente comando transfiere en streaming tres archivos desde un bucket de GCS a la tabla `trips` (la sintaxis `{0..2}` es un comodín para los valores 0, 1 y 2):

      ```sql theme={null}
      INSERT INTO nyc_taxi.trips_small
      SELECT
          trip_id,
          pickup_datetime,
          dropoff_datetime,
          pickup_longitude,
          pickup_latitude,
          dropoff_longitude,
          dropoff_latitude,
          passenger_count,
          trip_distance,
          fare_amount,
          extra,
          tip_amount,
          tolls_amount,
          total_amount,
          payment_type,
          pickup_ntaname,
          dropoff_ntaname
      FROM gcs(
          'https://storage.googleapis.com/clickhouse-public-datasets/nyc-taxi/trips_{0..2}.gz',
          'TabSeparatedWithNames'
      );
      ```
    </Tab>
  </Tabs>

  ## Consultas de muestra

  Las siguientes consultas se ejecutan sobre la muestra descrita anteriormente. Puede ejecutar las consultas de muestra en el conjunto de datos completo en [sql.clickhouse.com](https://sql.clickhouse.com/?query=U0VMRUNUIGNvdW50KCkgRlJPTSBueWNfdGF4aS50cmlwcw\&chart=eyJ0eXBlIjoibGluZSIsImNvbmZpZyI6eyJ0aXRsZSI6IlRlbXBlcmF0dXJlIGJ5IGNvdW50cnkgYW5kIHllYXIiLCJ4YXhpcyI6InllYXIiLCJ5YXhpcyI6ImNvdW50KCkiLCJzZXJpZXMiOiJDQVNUKHBhc3Nlbmdlcl9jb3VudCwgJ1N0cmluZycpIn19), modificando las consultas siguientes para usar la tabla `nyc_taxi.trips`.

  Veamos cuántas filas se insertaron:

  <RunnableCode>
    ```sql theme={null}
    SELECT count()
    FROM nyc_taxi.trips_small;
    ```
  </RunnableCode>

  Cada archivo TSV tiene aproximadamente 1 millón de filas, y los tres archivos tienen 3,000,317 filas. Veamos algunas:

  <RunnableCode>
    ```sql theme={null}
    SELECT *
    FROM nyc_taxi.trips_small
    LIMIT 10;
    ```
  </RunnableCode>

  Tenga en cuenta que hay columnas para las fechas de recogida y descenso, coordenadas geográficas, detalles de la tarifa, barrios de Nueva York y más.

  Ejecutemos algunas consultas. Esta consulta nos muestra los 10 barrios con las recogidas más frecuentes:

  <RunnableCode>
    ```sql theme={null}
    SELECT
       pickup_ntaname,
       count(*) AS count
    FROM nyc_taxi.trips_small WHERE pickup_ntaname != ''
    GROUP BY pickup_ntaname
    ORDER BY count DESC
    LIMIT 10;
    ```
  </RunnableCode>

  Esta consulta muestra la tarifa media en función del número de pasajeros:

  ```sql runnable view='chart' chart_config='eyJ0eXBlIjoiYmFyIiwiY29uZmlnIjp7InhheGlzIjoicGFzc2VuZ2VyX2NvdW50IiwieWF4aXMiOiJhdmcodG90YWxfYW1vdW50KSIsInRpdGxlIjoiQXZlcmFnZSBmYXJlIGJ5IHBhc3NlbmdlciBjb3VudCJ9fQ' theme={null}
  SELECT
     passenger_count,
     avg(total_amount)
  FROM nyc_taxi.trips_small
  WHERE passenger_count < 10
  GROUP BY passenger_count;
  ```

  Esta es la correlación entre el número de pasajeros y la distancia del viaje:

  ```sql runnable chart_config='eyJ0eXBlIjoiaG9yaXpvbnRhbCBiYXIiLCJjb25maWciOnsieGF4aXMiOiJwYXNzZW5nZXJfY291bnQiLCJ5YXhpcyI6ImRpc3RhbmNlIiwic2VyaWVzIjoiY291bnRyeSIsInRpdGxlIjoiQXZnIGZhcmUgYnkgcGFzc2VuZ2VyIGNvdW50In19' theme={null}
  SELECT
      passenger_count,
      avg(trip_distance) AS distance,
      count() AS c
  FROM nyc_taxi.trips_small
  GROUP BY passenger_count
  ORDER BY passenger_count ASC
  ```

  ## Descarga de particiones preparadas

  <Note>
    Los siguientes pasos ofrecen información sobre el conjunto de datos original y describen un método para cargar particiones preparadas en un entorno con un servidor de ClickHouse autogestionado.
  </Note>

  Consulte [https://github.com/toddwschneider/nyc-taxi-data](https://github.com/toddwschneider/nyc-taxi-data) y [http://tech.marksblogg.com/billion-nyc-taxi-rides-redshift.html](http://tech.marksblogg.com/billion-nyc-taxi-rides-redshift.html) para ver la descripción del conjunto de datos y las instrucciones de descarga.

  Al completar la descarga, obtendrá aproximadamente 227 GB de datos sin comprimir en archivos CSV. La descarga tarda alrededor de una hora con una conexión de 1 Gbit (la descarga en paralelo desde s3.amazonaws.com aprovecha al menos la mitad de un canal de 1 Gbit).
  Es posible que algunos archivos no se descarguen por completo. Compruebe el tamaño de los archivos y vuelva a descargar los que resulten sospechosos.

  ```bash theme={null}
  $ curl -O https://datasets.clickhouse.com/trips_mergetree/partitions/trips_mergetree.tar
  # Validate the checksum
  $ md5sum trips_mergetree.tar
  # Checksum should be equal to: f3b8d469b41d9a82da064ded7245d12c
  $ tar xvf trips_mergetree.tar -C /var/lib/clickhouse # path to ClickHouse data directory
  $ # check permissions of unpacked data, fix if required
  $ sudo service clickhouse-server restart
  $ clickhouse-client --query "select count(*) from datasets.trips_mergetree"
  ```

  <Info>
    Si va a ejecutar las consultas que se describen a continuación, debe usar el nombre de tabla completo, `datasets.trips_mergetree`.
  </Info>

  ## Resultados en un solo servidor

  Q1:

  ```sql theme={null}
  SELECT cab_type, count(*) FROM trips_mergetree GROUP BY cab_type;
  ```

  0.490 segundos.

  Q2:

  ```sql theme={null}
  SELECT passenger_count, avg(total_amount) FROM trips_mergetree GROUP BY passenger_count;
  ```

  1.224 segundos.

  Q3:

  ```sql theme={null}
  SELECT passenger_count, toYear(pickup_date) AS year, count(*) FROM trips_mergetree GROUP BY passenger_count, year;
  ```

  2.104 segundos.

  Q4:

  ```sql theme={null}
  SELECT passenger_count, toYear(pickup_date) AS year, round(trip_distance) AS distance, count(*)
  FROM trips_mergetree
  GROUP BY passenger_count, year, distance
  ORDER BY year, count(*) DESC;
  ```

  3.593 segundos.

  Se utilizó el siguiente servidor:

  Dos CPU Intel(R) Xeon(R) E5-2650 v2 @ 2.60GHz, 16 núcleos físicos en total, 128 GiB de RAM, 8 discos duros de 6 TB en RAID-5 por hardware

  El tiempo de ejecución corresponde a la mejor de tres ejecuciones. Sin embargo, a partir de la segunda ejecución, las consultas leen los datos de la caché del sistema de archivos. No se aplica ningún otro almacenamiento en caché: los datos se leen y se procesan en cada ejecución.

  Crear una tabla en tres servidores:

  En cada servidor:

  ```sql theme={null}
  CREATE TABLE default.trips_mergetree_third ( trip_id UInt32,  vendor_id Enum8('1' = 1, '2' = 2, 'CMT' = 3, 'VTS' = 4, 'DDS' = 5, 'B02512' = 10, 'B02598' = 11, 'B02617' = 12, 'B02682' = 13, 'B02764' = 14),  pickup_date Date,  pickup_datetime DateTime,  dropoff_date Date,  dropoff_datetime DateTime,  store_and_fwd_flag UInt8,  rate_code_id UInt8,  pickup_longitude Float64,  pickup_latitude Float64,  dropoff_longitude Float64,  dropoff_latitude Float64,  passenger_count UInt8,  trip_distance Float64,  fare_amount Float32,  extra Float32,  mta_tax Float32,  tip_amount Float32,  tolls_amount Float32,  ehail_fee Float32,  improvement_surcharge Float32,  total_amount Float32,  payment_type_ Enum8('UNK' = 0, 'CSH' = 1, 'CRE' = 2, 'NOC' = 3, 'DIS' = 4),  trip_type UInt8,  pickup FixedString(25),  dropoff FixedString(25),  cab_type Enum8('yellow' = 1, 'green' = 2, 'uber' = 3),  pickup_nyct2010_gid UInt8,  pickup_ctlabel Float32,  pickup_borocode UInt8,  pickup_boroname Enum8('' = 0, 'Manhattan' = 1, 'Bronx' = 2, 'Brooklyn' = 3, 'Queens' = 4, 'Staten Island' = 5),  pickup_ct2010 FixedString(6),  pickup_boroct2010 FixedString(7),  pickup_cdeligibil Enum8(' ' = 0, 'E' = 1, 'I' = 2),  pickup_ntacode FixedString(4),  pickup_ntaname Enum16('' = 0, 'Airport' = 1, 'Allerton-Pelham Gardens' = 2, 'Annadale-Huguenot-Prince\'s Bay-Eltingville' = 3, 'Arden Heights' = 4, 'Astoria' = 5, 'Auburndale' = 6, 'Baisley Park' = 7, 'Bath Beach' = 8, 'Battery Park City-Lower Manhattan' = 9, 'Bay Ridge' = 10, 'Bayside-Bayside Hills' = 11, 'Bedford' = 12, 'Bedford Park-Fordham North' = 13, 'Bellerose' = 14, 'Belmont' = 15, 'Bensonhurst East' = 16, 'Bensonhurst West' = 17, 'Borough Park' = 18, 'Breezy Point-Belle Harbor-Rockaway Park-Broad Channel' = 19, 'Briarwood-Jamaica Hills' = 20, 'Brighton Beach' = 21, 'Bronxdale' = 22, 'Brooklyn Heights-Cobble Hill' = 23, 'Brownsville' = 24, 'Bushwick North' = 25, 'Bushwick South' = 26, 'Cambria Heights' = 27, 'Canarsie' = 28, 'Carroll Gardens-Columbia Street-Red Hook' = 29, 'Central Harlem North-Polo Grounds' = 30, 'Central Harlem South' = 31, 'Charleston-Richmond Valley-Tottenville' = 32, 'Chinatown' = 33, 'Claremont-Bathgate' = 34, 'Clinton' = 35, 'Clinton Hill' = 36, 'Co-op City' = 37, 'College Point' = 38, 'Corona' = 39, 'Crotona Park East' = 40, 'Crown Heights North' = 41, 'Crown Heights South' = 42, 'Cypress Hills-City Line' = 43, 'DUMBO-Vinegar Hill-Downtown Brooklyn-Boerum Hill' = 44, 'Douglas Manor-Douglaston-Little Neck' = 45, 'Dyker Heights' = 46, 'East Concourse-Concourse Village' = 47, 'East Elmhurst' = 48, 'East Flatbush-Farragut' = 49, 'East Flushing' = 50, 'East Harlem North' = 51, 'East Harlem South' = 52, 'East New York' = 53, 'East New York (Pennsylvania Ave)' = 54, 'East Tremont' = 55, 'East Village' = 56, 'East Williamsburg' = 57, 'Eastchester-Edenwald-Baychester' = 58, 'Elmhurst' = 59, 'Elmhurst-Maspeth' = 60, 'Erasmus' = 61, 'Far Rockaway-Bayswater' = 62, 'Flatbush' = 63, 'Flatlands' = 64, 'Flushing' = 65, 'Fordham South' = 66, 'Forest Hills' = 67, 'Fort Greene' = 68, 'Fresh Meadows-Utopia' = 69, 'Ft. Totten-Bay Terrace-Clearview' = 70, 'Georgetown-Marine Park-Bergen Beach-Mill Basin' = 71, 'Glen Oaks-Floral Park-New Hyde Park' = 72, 'Glendale' = 73, 'Gramercy' = 74, 'Grasmere-Arrochar-Ft. Wadsworth' = 75, 'Gravesend' = 76, 'Great Kills' = 77, 'Greenpoint' = 78, 'Grymes Hill-Clifton-Fox Hills' = 79, 'Hamilton Heights' = 80, 'Hammels-Arverne-Edgemere' = 81, 'Highbridge' = 82, 'Hollis' = 83, 'Homecrest' = 84, 'Hudson Yards-Chelsea-Flatiron-Union Square' = 85, 'Hunters Point-Sunnyside-West Maspeth' = 86, 'Hunts Point' = 87, 'Jackson Heights' = 88, 'Jamaica' = 89, 'Jamaica Estates-Holliswood' = 90, 'Kensington-Ocean Parkway' = 91, 'Kew Gardens' = 92, 'Kew Gardens Hills' = 93, 'Kingsbridge Heights' = 94, 'Laurelton' = 95, 'Lenox Hill-Roosevelt Island' = 96, 'Lincoln Square' = 97, 'Lindenwood-Howard Beach' = 98, 'Longwood' = 99, 'Lower East Side' = 100, 'Madison' = 101, 'Manhattanville' = 102, 'Marble Hill-Inwood' = 103, 'Mariner\'s Harbor-Arlington-Port Ivory-Graniteville' = 104, 'Maspeth' = 105, 'Melrose South-Mott Haven North' = 106, 'Middle Village' = 107, 'Midtown-Midtown South' = 108, 'Midwood' = 109, 'Morningside Heights' = 110, 'Morrisania-Melrose' = 111, 'Mott Haven-Port Morris' = 112, 'Mount Hope' = 113, 'Murray Hill' = 114, 'Murray Hill-Kips Bay' = 115, 'New Brighton-Silver Lake' = 116, 'New Dorp-Midland Beach' = 117, 'New Springville-Bloomfield-Travis' = 118, 'North Corona' = 119, 'North Riverdale-Fieldston-Riverdale' = 120, 'North Side-South Side' = 121, 'Norwood' = 122, 'Oakland Gardens' = 123, 'Oakwood-Oakwood Beach' = 124, 'Ocean Hill' = 125, 'Ocean Parkway South' = 126, 'Old Astoria' = 127, 'Old Town-Dongan Hills-South Beach' = 128, 'Ozone Park' = 129, 'Park Slope-Gowanus' = 130, 'Parkchester' = 131, 'Pelham Bay-Country Club-City Island' = 132, 'Pelham Parkway' = 133, 'Pomonok-Flushing Heights-Hillcrest' = 134, 'Port Richmond' = 135, 'Prospect Heights' = 136, 'Prospect Lefferts Gardens-Wingate' = 137, 'Queens Village' = 138, 'Queensboro Hill' = 139, 'Queensbridge-Ravenswood-Long Island City' = 140, 'Rego Park' = 141, 'Richmond Hill' = 142, 'Ridgewood' = 143, 'Rikers Island' = 144, 'Rosedale' = 145, 'Rossville-Woodrow' = 146, 'Rugby-Remsen Village' = 147, 'Schuylerville-Throgs Neck-Edgewater Park' = 148, 'Seagate-Coney Island' = 149, 'Sheepshead Bay-Gerritsen Beach-Manhattan Beach' = 150, 'SoHo-TriBeCa-Civic Center-Little Italy' = 151, 'Soundview-Bruckner' = 152, 'Soundview-Castle Hill-Clason Point-Harding Park' = 153, 'South Jamaica' = 154, 'South Ozone Park' = 155, 'Springfield Gardens North' = 156, 'Springfield Gardens South-Brookville' = 157, 'Spuyten Duyvil-Kingsbridge' = 158, 'St. Albans' = 159, 'Stapleton-Rosebank' = 160, 'Starrett City' = 161, 'Steinway' = 162, 'Stuyvesant Heights' = 163, 'Stuyvesant Town-Cooper Village' = 164, 'Sunset Park East' = 165, 'Sunset Park West' = 166, 'Todt Hill-Emerson Hill-Heartland Village-Lighthouse Hill' = 167, 'Turtle Bay-East Midtown' = 168, 'University Heights-Morris Heights' = 169, 'Upper East Side-Carnegie Hill' = 170, 'Upper West Side' = 171, 'Van Cortlandt Village' = 172, 'Van Nest-Morris Park-Westchester Square' = 173, 'Washington Heights North' = 174, 'Washington Heights South' = 175, 'West Brighton' = 176, 'West Concourse' = 177, 'West Farms-Bronx River' = 178, 'West New Brighton-New Brighton-St. George' = 179, 'West Village' = 180, 'Westchester-Unionport' = 181, 'Westerleigh' = 182, 'Whitestone' = 183, 'Williamsbridge-Olinville' = 184, 'Williamsburg' = 185, 'Windsor Terrace' = 186, 'Woodhaven' = 187, 'Woodlawn-Wakefield' = 188, 'Woodside' = 189, 'Yorkville' = 190, 'park-cemetery-etc-Bronx' = 191, 'park-cemetery-etc-Brooklyn' = 192, 'park-cemetery-etc-Manhattan' = 193, 'park-cemetery-etc-Queens' = 194, 'park-cemetery-etc-Staten Island' = 195),  pickup_puma UInt16,  dropoff_nyct2010_gid UInt8,  dropoff_ctlabel Float32,  dropoff_borocode UInt8,  dropoff_boroname Enum8('' = 0, 'Manhattan' = 1, 'Bronx' = 2, 'Brooklyn' = 3, 'Queens' = 4, 'Staten Island' = 5),  dropoff_ct2010 FixedString(6),  dropoff_boroct2010 FixedString(7),  dropoff_cdeligibil Enum8(' ' = 0, 'E' = 1, 'I' = 2),  dropoff_ntacode FixedString(4),  dropoff_ntaname Enum16('' = 0, 'Airport' = 1, 'Allerton-Pelham Gardens' = 2, 'Annadale-Huguenot-Prince\'s Bay-Eltingville' = 3, 'Arden Heights' = 4, 'Astoria' = 5, 'Auburndale' = 6, 'Baisley Park' = 7, 'Bath Beach' = 8, 'Battery Park City-Lower Manhattan' = 9, 'Bay Ridge' = 10, 'Bayside-Bayside Hills' = 11, 'Bedford' = 12, 'Bedford Park-Fordham North' = 13, 'Bellerose' = 14, 'Belmont' = 15, 'Bensonhurst East' = 16, 'Bensonhurst West' = 17, 'Borough Park' = 18, 'Breezy Point-Belle Harbor-Rockaway Park-Broad Channel' = 19, 'Briarwood-Jamaica Hills' = 20, 'Brighton Beach' = 21, 'Bronxdale' = 22, 'Brooklyn Heights-Cobble Hill' = 23, 'Brownsville' = 24, 'Bushwick North' = 25, 'Bushwick South' = 26, 'Cambria Heights' = 27, 'Canarsie' = 28, 'Carroll Gardens-Columbia Street-Red Hook' = 29, 'Central Harlem North-Polo Grounds' = 30, 'Central Harlem South' = 31, 'Charleston-Richmond Valley-Tottenville' = 32, 'Chinatown' = 33, 'Claremont-Bathgate' = 34, 'Clinton' = 35, 'Clinton Hill' = 36, 'Co-op City' = 37, 'College Point' = 38, 'Corona' = 39, 'Crotona Park East' = 40, 'Crown Heights North' = 41, 'Crown Heights South' = 42, 'Cypress Hills-City Line' = 43, 'DUMBO-Vinegar Hill-Downtown Brooklyn-Boerum Hill' = 44, 'Douglas Manor-Douglaston-Little Neck' = 45, 'Dyker Heights' = 46, 'East Concourse-Concourse Village' = 47, 'East Elmhurst' = 48, 'East Flatbush-Farragut' = 49, 'East Flushing' = 50, 'East Harlem North' = 51, 'East Harlem South' = 52, 'East New York' = 53, 'East New York (Pennsylvania Ave)' = 54, 'East Tremont' = 55, 'East Village' = 56, 'East Williamsburg' = 57, 'Eastchester-Edenwald-Baychester' = 58, 'Elmhurst' = 59, 'Elmhurst-Maspeth' = 60, 'Erasmus' = 61, 'Far Rockaway-Bayswater' = 62, 'Flatbush' = 63, 'Flatlands' = 64, 'Flushing' = 65, 'Fordham South' = 66, 'Forest Hills' = 67, 'Fort Greene' = 68, 'Fresh Meadows-Utopia' = 69, 'Ft. Totten-Bay Terrace-Clearview' = 70, 'Georgetown-Marine Park-Bergen Beach-Mill Basin' = 71, 'Glen Oaks-Floral Park-New Hyde Park' = 72, 'Glendale' = 73, 'Gramercy' = 74, 'Grasmere-Arrochar-Ft. Wadsworth' = 75, 'Gravesend' = 76, 'Great Kills' = 77, 'Greenpoint' = 78, 'Grymes Hill-Clifton-Fox Hills' = 79, 'Hamilton Heights' = 80, 'Hammels-Arverne-Edgemere' = 81, 'Highbridge' = 82, 'Hollis' = 83, 'Homecrest' = 84, 'Hudson Yards-Chelsea-Flatiron-Union Square' = 85, 'Hunters Point-Sunnyside-West Maspeth' = 86, 'Hunts Point' = 87, 'Jackson Heights' = 88, 'Jamaica' = 89, 'Jamaica Estates-Holliswood' = 90, 'Kensington-Ocean Parkway' = 91, 'Kew Gardens' = 92, 'Kew Gardens Hills' = 93, 'Kingsbridge Heights' = 94, 'Laurelton' = 95, 'Lenox Hill-Roosevelt Island' = 96, 'Lincoln Square' = 97, 'Lindenwood-Howard Beach' = 98, 'Longwood' = 99, 'Lower East Side' = 100, 'Madison' = 101, 'Manhattanville' = 102, 'Marble Hill-Inwood' = 103, 'Mariner\'s Harbor-Arlington-Port Ivory-Graniteville' = 104, 'Maspeth' = 105, 'Melrose South-Mott Haven North' = 106, 'Middle Village' = 107, 'Midtown-Midtown South' = 108, 'Midwood' = 109, 'Morningside Heights' = 110, 'Morrisania-Melrose' = 111, 'Mott Haven-Port Morris' = 112, 'Mount Hope' = 113, 'Murray Hill' = 114, 'Murray Hill-Kips Bay' = 115, 'New Brighton-Silver Lake' = 116, 'New Dorp-Midland Beach' = 117, 'New Springville-Bloomfield-Travis' = 118, 'North Corona' = 119, 'North Riverdale-Fieldston-Riverdale' = 120, 'North Side-South Side' = 121, 'Norwood' = 122, 'Oakland Gardens' = 123, 'Oakwood-Oakwood Beach' = 124, 'Ocean Hill' = 125, 'Ocean Parkway South' = 126, 'Old Astoria' = 127, 'Old Town-Dongan Hills-South Beach' = 128, 'Ozone Park' = 129, 'Park Slope-Gowanus' = 130, 'Parkchester' = 131, 'Pelham Bay-Country Club-City Island' = 132, 'Pelham Parkway' = 133, 'Pomonok-Flushing Heights-Hillcrest' = 134, 'Port Richmond' = 135, 'Prospect Heights' = 136, 'Prospect Lefferts Gardens-Wingate' = 137, 'Queens Village' = 138, 'Queensboro Hill' = 139, 'Queensbridge-Ravenswood-Long Island City' = 140, 'Rego Park' = 141, 'Richmond Hill' = 142, 'Ridgewood' = 143, 'Rikers Island' = 144, 'Rosedale' = 145, 'Rossville-Woodrow' = 146, 'Rugby-Remsen Village' = 147, 'Schuylerville-Throgs Neck-Edgewater Park' = 148, 'Seagate-Coney Island' = 149, 'Sheepshead Bay-Gerritsen Beach-Manhattan Beach' = 150, 'SoHo-TriBeCa-Civic Center-Little Italy' = 151, 'Soundview-Bruckner' = 152, 'Soundview-Castle Hill-Clason Point-Harding Park' = 153, 'South Jamaica' = 154, 'South Ozone Park' = 155, 'Springfield Gardens North' = 156, 'Springfield Gardens South-Brookville' = 157, 'Spuyten Duyvil-Kingsbridge' = 158, 'St. Albans' = 159, 'Stapleton-Rosebank' = 160, 'Starrett City' = 161, 'Steinway' = 162, 'Stuyvesant Heights' = 163, 'Stuyvesant Town-Cooper Village' = 164, 'Sunset Park East' = 165, 'Sunset Park West' = 166, 'Todt Hill-Emerson Hill-Heartland Village-Lighthouse Hill' = 167, 'Turtle Bay-East Midtown' = 168, 'University Heights-Morris Heights' = 169, 'Upper East Side-Carnegie Hill' = 170, 'Upper West Side' = 171, 'Van Cortlandt Village' = 172, 'Van Nest-Morris Park-Westchester Square' = 173, 'Washington Heights North' = 174, 'Washington Heights South' = 175, 'West Brighton' = 176, 'West Concourse' = 177, 'West Farms-Bronx River' = 178, 'West New Brighton-New Brighton-St. George' = 179, 'West Village' = 180, 'Westchester-Unionport' = 181, 'Westerleigh' = 182, 'Whitestone' = 183, 'Williamsbridge-Olinville' = 184, 'Williamsburg' = 185, 'Windsor Terrace' = 186, 'Woodhaven' = 187, 'Woodlawn-Wakefield' = 188, 'Woodside' = 189, 'Yorkville' = 190, 'park-cemetery-etc-Bronx' = 191, 'park-cemetery-etc-Brooklyn' = 192, 'park-cemetery-etc-Manhattan' = 193, 'park-cemetery-etc-Queens' = 194, 'park-cemetery-etc-Staten Island' = 195),  dropoff_puma UInt16) ENGINE = MergeTree(pickup_date, pickup_datetime, 8192);
  ```

  En el servidor de origen:

  ```sql theme={null}
  CREATE TABLE trips_mergetree_x3 AS trips_mergetree_third ENGINE = Distributed(perftest, default, trips_mergetree_third, rand());
  ```

  La siguiente consulta redistribuye los datos:

  ```sql theme={null}
  INSERT INTO trips_mergetree_x3 SELECT * FROM trips_mergetree;
  ```

  Esto tarda 2454 segundos.

  En tres servidores:

  Q1: 0.212 segundos.
  Q2: 0.438 segundos.
  Q3: 0.733 segundos.
  Q4: 1.241 segundos.

  Nada sorprendente, ya que las consultas escalan de forma lineal.

  También disponemos de los resultados de un cluster de 140 servidores:

  Q1: 0.028 s
  Q2: 0.043 s
  Q3: 0.051 s
  Q4: 0.072 s

  En este caso, el tiempo de procesamiento de la consulta depende, sobre todo, de la latencia de red.
  Ejecutamos las consultas con un client ubicado en un centro de datos distinto al del cluster, lo que añadió unos 20 ms de latencia.

  ## Resumen

  | servidores | Q1 | Q2 | Q3 | Q4 |
  | - | - | - | - | - |
  | 1, E5-2650v2 | 0.490 | 1.224 | 2.104 | 3.593 |
  | 3, E5-2650v2 | 0.212 | 0.438 | 0.733 | 1.241 |
  | 1, AWS c5n.4xlarge | 0.249 | 1.279 | 1.738 | 3.527 |
  | 1, AWS c5n.9xlarge | 0.130 | 0.584 | 0.777 | 1.811 |
  | 3, AWS c5n.9xlarge | 0.057 | 0.231 | 0.285 | 0.641 |
  | 140, E5-2650v2 | 0.028 | 0.043 | 0.051 | 0.072 |
</View>
